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:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
version: osslsigncode-2.7
version: osslsigncode-2.8
jobs:
build:
@ -90,12 +90,28 @@ jobs:
with:
arch: ${{matrix.arch}}
- name: Install MSYS2
if: matrix.compiler == 'mingw'
uses: msys2/setup-msys2@v2
with:
update: true
install: mingw-w64-x86_64-ninja
- name: Put MSYS2_MinGW64 on PATH
if: matrix.compiler == 'mingw'
run: echo "D:/a/_temp/msys64/mingw64/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Install apt dependencies (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
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)
if: runner.os == 'macOS'
uses: maxim-lobanov/setup-xcode@v1
@ -129,8 +145,8 @@ jobs:
working-directory: ${{github.workspace}}/build
if: runner.os == 'macOS'
run: |
python3 --version
python3 ./Testing/server_http.py --port 19254
python3.8 --version
python3.8 ./Testing/server_http.py --port 19254
while test ! -s ./Testing/logs/port.log; do sleep 1; done
- name: Start HTTP server (Windows)

View File

@ -10,7 +10,7 @@ set(BUILTIN_SOCKET ON CACHE BOOL "") # for static Python
# configure basic project information
project(osslsigncode
VERSION 2.7
VERSION 2.8
DESCRIPTION "OpenSSL based Authenticode signing for PE, CAB, CAT and MSI files"
HOMEPAGE_URL "https://github.com/mtrojnar/osslsigncode"
LANGUAGES C)
@ -48,7 +48,7 @@ configure_file(Config.h.in config.h)
target_compile_definitions(osslsigncode PRIVATE HAVE_CONFIG_H=1)
# 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)
target_sources(osslsigncode PRIVATE applink.c)
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.
```
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 \
-D 'PACKAGE_STRING="osslsigncode x.y"' \
-D 'PACKAGE_BUGREPORT="Your.Email@example.com"' \
@ -71,7 +71,7 @@
3) Build 64-bit Windows executables.
```
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 \
-I 'C:/OpenSSL/include/' \
-L 'C:/curl/lib' -lcurl \

22
NEWS.md
View File

@ -1,5 +1,27 @@
# 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)
- 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:
```
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:
```

304
appx.c
View File

@ -6,6 +6,7 @@
* Copyright (C) 2023 Michał Trojnara <Michal.Trojnara@stunnel.org>
* Author: Małgorzata Olszówka <Malgorzata.Olszowka@stunnel.org>
*
* APPX files do not support nesting (multiple signature)
*/
#define _FILE_OFFSET_BITS 64
@ -16,10 +17,22 @@
#include <zlib.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)
#define fseeko _fseeki64
#define ftello _ftelli64
#endif
#endif /* _MSC_VER */
#define EOCDR_SIZE 22
#define ZIP64_EOCD_LOCATOR_SIZE 20
@ -233,26 +246,30 @@ struct appx_ctx_st {
/* FILE_FORMAT method prototypes */
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 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_check_file(FILE_FORMAT_CTX *ctx, int detached);
static int appx_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
static PKCS7 *appx_pkcs7_extract(FILE_FORMAT_CTX *ctx);
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 BIO *appx_bio_free(BIO *hash, BIO *outdata);
static void appx_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static void appx_bio_free(BIO *hash, BIO *outdata);
static void appx_ctx_cleanup(FILE_FORMAT_CTX *ctx);
FILE_FORMAT file_format_appx = {
.ctx_new = appx_ctx_new,
.md_get = appx_md_get,
.data_blob_get = appx_spc_sip_info_get,
.pkcs7_contents_get = appx_pkcs7_contents_get,
.hash_length_get = appx_hash_length_get,
.check_file = appx_check_file,
.verify_digests = appx_verify_digests,
.pkcs7_extract = appx_pkcs7_extract,
.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,
.bio_free = appx_bio_free,
.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 int zipEntryExist(ZIP_FILE *zip, const char *name);
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 int zipReadFileData(ZIP_FILE *zip, uint8_t **pData, uint64_t *dataSize, ZIP_CENTRAL_DIRECTORY_ENTRY *entry);
static size_t zipReadFileDataByName(uint8_t **pData, ZIP_FILE *zip, const char *name);
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 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);
@ -344,10 +361,8 @@ static FILE_FORMAT_CTX *appx_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *ou
if (zipGetCDEntryByName(zip, APPXBUNDLE_MANIFEST_FILENAME)) {
ctx->appx_ctx->isBundle = 1;
}
if (options->nest)
/* I've not tried using set_nested_signature as signtool won't do this */
printf("Warning: APPX files do not support nesting (multiple signature)\n");
if (options->cmd == CMD_SIGN || options->cmd==CMD_ATTACH || options->cmd==CMD_ADD) {
if (options->cmd == CMD_SIGN || options->cmd==CMD_ATTACH
|| options->cmd==CMD_ADD || options->cmd == CMD_EXTRACT_DATA) {
printf("Warning: Ignore -h option, use the hash algorithm specified in AppxBlockMap.xml\n");
}
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 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.
* [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 */
}
/*
* 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.
* [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;
}
/*
* 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.
* [in] ctx: structure holds input and output data
@ -470,9 +511,15 @@ static PKCS7 *appx_pkcs7_extract(FILE_FORMAT_CTX *ctx)
PKCS7 *p7;
uint8_t *data = NULL;
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 */
}
/* 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)
{
uint8_t *data = NULL;
size_t dataSize;
uint64_t cdOffset, noEntries = 0;
ZIP_FILE *zip = ctx->appx_ctx->zip;
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");
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)) {
printf("Failed to remove signature entry\n");
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
* [out] hash: message digest 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 */
(void)outdata;
(void)hash;
if (ctx->options->cmd == CMD_ADD || ctx->options->cmd == CMD_ATTACH) {
/* 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);
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 */
}
/* create hash blob from concatenated APPX hashes */
hashes = appx_calculate_hashes(ctx);
if (!hashes) {
return NULL; /* FAILED */
}
/* Create a new PKCS#7 signature */
p7 = pkcs7_create(ctx);
if (!p7) {
printf("Creating a new signature failed\n");
return NULL; /* FAILED */
}
if (!add_indirect_data_object(p7, hashes, ctx)) {
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
BIO_free_all(hashes);
PKCS7_free(p7);
return NULL; /* FAILED */
}
BIO_free_all(hashes);
/* 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 1; /* FAILED */
}
if (!appx_append_ct_signature_entry(ctx->appx_ctx->zip, entry)) {
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 (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);
if (!hashes) {
return NULL; /* FAILED */
}
p7 = pkcs7_create(ctx);
if (!p7) {
printf("Creating a new signature failed\n");
BIO_free_all(hashes);
return NULL; /* FAILED */
}
if (!add_indirect_data_object(p7)) {
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
PKCS7_free(p7);
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);
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; /* OK */
}
@ -684,27 +757,21 @@ static int appx_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
* [out] outdata: outdata file BIO
* [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(hash);
return NULL; /* OK */
}
/*
* Deallocate a FILE_FORMAT_CTX structure and PE format specific structure,
* unmap indata file, unlink outfile.
* Deallocate a FILE_FORMAT_CTX structure and PE format specific structure.
* [out] ctx: structure holds input and output data
* [out] hash: message digest BIO
* [in] outdata: outdata file BIO
* [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);
OPENSSL_free(ctx->appx_ctx->calculatedBMHash);
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;
int ret;
if (!zipReadFileData(zip, &data, (uint64_t *)&dataSize, entry)) {
dataSize = zipReadFileData(zip, &data, entry);
if (dataSize <= 0) {
return 0; /* FAILED */
}
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;
int ret;
if (!zipReadFileData(zip, &data, (uint64_t *)&dataSize, entry)) {
dataSize = zipReadFileData(zip, &data, entry);
if (dataSize <= 0) {
return 0; /* FAILED */
}
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)
{
uint8_t *data = NULL;
uint64_t dataSize = 0;
char *start, *end, *pos;
char *valueStart = NULL, *valueEnd = 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);
return NULL; /* FAILED */
}
@ -1527,7 +1596,7 @@ static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO
memset(&header, 0, sizeof(header));
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 */
}
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 */
}
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 */
}
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)
{
uint8_t *data = NULL;
uint64_t dataSize = 0;
size_t dataSize;
u_char *mdbuf = NULL;
BIO *bhash;
if (!zipReadFileDataByName(&data, &dataSize, zip, fileName)) {
dataSize = zipReadFileDataByName(&data, zip, fileName);
if (dataSize <= 0) {
return NULL; /* FAILED */
}
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.
* [out] pData: pointer to data
* [out] dataSize: data size
* [in] zip: structure holds specific ZIP data
* [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;
uint64_t noEntries = 0;
@ -1729,7 +1798,7 @@ static int zipReadFileDataByName(uint8_t **pData, uint64_t *dataSize, ZIP_FILE *
return 0; /* FAILED */
}
if (!strcmp(entry->fileName, name)) {
return zipReadFileData(zip, pData, dataSize, entry);
return zipReadFileData(zip, pData, entry);
}
}
return 0; /* FAILED */
@ -1739,20 +1808,19 @@ static int zipReadFileDataByName(uint8_t **pData, uint64_t *dataSize, ZIP_FILE *
* Read file data.
* [in, out] zip: structure holds specific ZIP data
* [out] pData: pointer to data
* [out] dataSize: data size
* [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;
uint8_t *compressedData = NULL;
uint64_t compressedSize = 0;
uint64_t uncompressedSize = 0;
size_t size;
size_t size, dataSize = 0;
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 */
}
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);
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 */
}
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;
}
if (entry->compression == COMPRESSION_NONE) {
if (compressedSize == 0) {
OPENSSL_free(compressedData);
return 0; /* FAILED */
}
*pData = compressedData;
*dataSize = compressedSize;
dataSize = compressedSize;
} else if (entry->compression == COMPRESSION_DEFLATE) {
uint8_t *uncompressedData = OPENSSL_zalloc(uncompressedSize + 1);
uint64_t destLen = uncompressedSize;
uint64_t sourceLen = compressedSize;
int ret;
ret = zipInflate(uncompressedData, &destLen, compressedData, &sourceLen);
ret = zipInflate(uncompressedData, &destLen, compressedData, (uLong *)&sourceLen);
OPENSSL_free(compressedData);
if (ret != Z_OK) {
@ -1812,15 +1884,19 @@ static int zipReadFileData(ZIP_FILE *zip, uint8_t **pData, uint64_t *dataSize, Z
OPENSSL_free(uncompressedData);
return 0; /* FAILED */
} else {
if (destLen == 0) {
OPENSSL_free(uncompressedData);
return 0; /* FAILED */
}
*pData = uncompressedData;
*dataSize = destLen;
dataSize = destLen;
}
} else {
printf("Unsupported compression mode: %d\n", entry->compression);
OPENSSL_free(compressedData);
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 */
}
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 */
}
if (fseeko(file, (int64_t)compressedSize, SEEK_CUR) < 0) {
@ -2133,7 +2209,7 @@ static ZIP_FILE *openZip(const char *filename)
return NULL; /* FAILED */
}
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);
return 0; /* FAILED */
}
@ -2162,13 +2238,13 @@ static ZIP_FILE *openZip(const char *filename)
zip->centralDirectorySize = zip->eocdr.centralDirectorySize;
zip->centralDirectoryRecordCount = (uint64_t)zip->eocdr.totalEntries;
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);
return NULL; /* FAILED */
}
}
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);
return NULL; /* FAILED */
}
@ -2560,7 +2636,7 @@ static int readZip64EOCDR(ZIP64_EOCDR *eocdr, FILE *file, uint64_t offset)
/* zip64 extensible data sector (comment) */
eocdr->commentLen = eocdr->eocdrSize - 44;
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 */
}
if (eocdr->commentLen > 0) {

237
cab.c
View File

@ -43,32 +43,38 @@ struct cab_ctx_st {
/* FILE_FORMAT method prototypes */
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 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_check_file(FILE_FORMAT_CTX *ctx, int detached);
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 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 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 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_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static void cab_bio_free(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 = {
.ctx_new = cab_ctx_new,
.data_blob_get = cab_obsolete_link_get,
.pkcs7_contents_get = cab_pkcs7_contents_get,
.hash_length_get = cab_hash_length_get,
.check_file = cab_check_file,
.digest_calc = cab_digest_calc,
.verify_digests = cab_verify_digests,
.pkcs7_extract = cab_pkcs7_extract,
.pkcs7_extract_to_nest = cab_pkcs7_extract_to_nest,
.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,
.update_data_size = cab_update_data_size,
.bio_free = cab_bio_free,
.ctx_cleanup = cab_ctx_cleanup
.ctx_cleanup = cab_ctx_cleanup,
.is_detaching_supported = cab_is_detaching_supported
};
/* 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 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_check_file(FILE_FORMAT_CTX *ctx);
/*
* 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 */
}
if (memcmp(options->indata, "MSCF", 4)) {
unmap_file(options->infile, filesize);
unmap_file(options->indata, filesize);
return NULL; /* FAILED */
}
cab_ctx = cab_ctx_get(options->indata, filesize);
if (!cab_ctx) {
unmap_file(options->infile, filesize);
unmap_file(options->indata, filesize);
return NULL; /* FAILED */
}
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 */
}
/*
* 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
* [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);
}
/*
* 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.
* [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)
{
if (ctx->cab_ctx->sigpos == 0 || ctx->cab_ctx->siglen == 0
|| ctx->cab_ctx->sigpos > ctx->cab_ctx->fileend) {
const u_char *blob;
if (!cab_check_file(ctx)) {
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;
uint32_t tmp;
uint16_t nfolders, flags;
char *buf = OPENSSL_malloc(SIZE_64K);
char *buf;
/* squash the unused parameter warning */
(void)hash;
if (!cab_check_file(ctx)) {
return 1; /* FAILED, no signature */
}
buf = OPENSSL_malloc(SIZE_64K);
/*
* u1 signature[4] 4643534D MSCF: 0-3
* u4 reserved1 00000000: 4-7
@ -448,64 +469,62 @@ 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
* [out] hash: message digest 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 */
if (ctx->cab_ctx->header_size == 20) {
if (!cab_modify_header(ctx, hash, outdata))
return NULL; /* FAILED */
return 1; /* FAILED */
} else {
if (!cab_add_header(ctx, hash, outdata))
return NULL; /* FAILED */
return 1; /* 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)
|| 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;
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 *cab_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 (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) {
printf("Creating a new signature failed\n");
return NULL; /* FAILED */
}
if (ctx->options->jp >= 0 && !cab_add_jp_attribute(p7, ctx->options->jp)) {
printf("Adding jp attribute failed\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
if (!add_indirect_data_object(p7, hash, ctx)) {
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
if (ctx->options->jp >= 0 && !cab_add_jp_attribute(p7, ctx->options->jp)) {
printf("Adding jp attribute failed\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
if (ctx->options->nest)
ctx->options->prevsig = cursig;
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;
}
@ -580,40 +599,33 @@ static void cab_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
* [out] outdata: outdata file BIO (unused)
* [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 */
(void)outdata;
BIO_free_all(hash);
return NULL;
}
/*
* 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
* [out] hash: message digest BIO
* [in] outdata: outdata file BIO
* [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);
OPENSSL_free(ctx->cab_ctx);
OPENSSL_free(ctx);
}
static int cab_is_detaching_supported(void)
{
return 1; /* OK */
}
/*
* CAB helper functions
*/
@ -931,6 +943,29 @@ static int cab_add_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
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:
c-basic-offset: 4

401
cat.c
View File

@ -5,34 +5,49 @@
* Author: Małgorzata Olszówka <Malgorzata.Olszowka@stunnel.org>
*
* Catalog files are a bit odd, in that they are only a PKCS7 blob.
* CAT files do not support nesting (multiple signature)
*/
#include "osslsigncode.h"
#include "helpers.h"
const u_char pkcs7_signed_data[] = {
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x07, 0x02,
};
typedef struct {
ASN1_BMPSTRING *tag;
ASN1_INTEGER *flags;
ASN1_OCTET_STRING *value;
} CatNameValueContent;
DECLARE_ASN1_FUNCTIONS(CatNameValueContent)
ASN1_SEQUENCE(CatNameValueContent) = {
ASN1_SIMPLE(CatNameValueContent, tag, ASN1_BMPSTRING),
ASN1_SIMPLE(CatNameValueContent, flags, ASN1_INTEGER),
ASN1_SIMPLE(CatNameValueContent, value, ASN1_OCTET_STRING)
} ASN1_SEQUENCE_END(CatNameValueContent)
IMPLEMENT_ASN1_FUNCTIONS(CatNameValueContent)
struct cat_ctx_st {
uint32_t sigpos;
uint32_t siglen;
uint32_t fileend;
PKCS7 *p7;
};
/* FILE_FORMAT method prototypes */
static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
static int cat_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx);
static PKCS7 *cat_pkcs7_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 BIO *cat_bio_free(BIO *hash, BIO *outdata);
static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static void cat_bio_free(BIO *hash, BIO *outdata);
static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx);
FILE_FORMAT file_format_cat = {
.ctx_new = cat_ctx_new,
.verify_digests = cat_verify_digests,
.pkcs7_extract = cat_pkcs7_extract,
.pkcs7_prepare = cat_pkcs7_prepare,
.pkcs7_signature_new = cat_pkcs7_signature_new,
.append_pkcs7 = cat_append_pkcs7,
.bio_free = cat_bio_free,
.ctx_cleanup = cat_ctx_cleanup,
@ -40,6 +55,14 @@ FILE_FORMAT file_format_cat = {
/* Prototypes */
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize);
static int cat_add_ms_ctl_object(PKCS7 *p7);
static int cat_sign_ms_ctl_content(PKCS7 *p7, PKCS7 *contents);
static int cat_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
@ -58,18 +81,10 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
CAT_CTX *cat_ctx;
uint32_t filesize;
/* squash unused parameter warnings */
(void)outdata;
(void)hash;
if (options->cmd == CMD_REMOVE || options->cmd==CMD_ATTACH) {
if (options->cmd == CMD_REMOVE || options->cmd==CMD_ATTACH || options->cmd == CMD_EXTRACT_DATA) {
printf("Unsupported command\n");
return NULL; /* FAILED */
}
if (options->cmd == CMD_VERIFY) {
printf("Use -catalog option\n");
return NULL; /* FAILED */
}
filesize = get_file_size(options->infile);
if (filesize == 0)
return NULL; /* FAILED */
@ -78,15 +93,9 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
if (!options->indata) {
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);
if (!cat_ctx) {
unmap_file(options->infile, filesize);
unmap_file(options->indata, filesize);
return NULL; /* FAILED */
}
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 */
BIO_push(hash, outdata);
if (options->nest)
/* I've not tried using set_nested_signature as signtool won't do this */
printf("Warning: CAT files do not support nesting (multiple signature)\n");
if (options->cmd == CMD_VERIFY)
printf("Warning: Use -catalog option to verify that a file, listed in catalog file, is signed\n");
if (options->jp >= 0)
printf("Warning: -jp option is only valid for CAB files\n");
if (options->pagehash == 1)
@ -109,6 +117,19 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
return ctx;
}
/*
* ContentInfo value is the inner content of pkcs7-signedData.
* An extra verification is not necessary when a content type data
* is the inner content of the signed-data type.
*/
static int cat_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
{
/* squash unused parameter warnings */
(void)ctx;
(void)p7;
return 1; /* OK */
}
/*
* Extract existing signature in DER format.
* [in] ctx: structure holds input and output data
@ -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)
{
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
* [out] hash: message digest BIO (unused)
* [out] outdata: outdata file BIO (unused)
* [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 */
(void)outdata;
(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");
p7 = pkcs7_create(ctx);
if (!p7) {
printf("Creating a new signature failed\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);
if (!p7) {
printf("Creating a new signature failed\n");
PKCS7_free(cursig);
return NULL; /* FAILED */
}
if (!add_ms_ctl_object(p7, cursig)) {
printf("Adding MS_CTL_OBJID failed\n");
PKCS7_free(p7);
PKCS7_free(cursig);
return NULL; /* FAILED */
}
PKCS7_free(cursig);
if (!cat_add_ms_ctl_object(p7)) {
printf("Adding MS_CTL_OBJID failed\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
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 */
}
/*
* 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
* [in] p7: PKCS#7 signature
* [returns] 1 on error or 0 on success
*/
static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
{
u_char *p = NULL;
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 */
return data_write_pkcs7(ctx, outdata, p7);
}
/*
@ -194,36 +192,25 @@ static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
* [out] outdata: outdata file BIO (unused)
* [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 */
(void)outdata;
BIO_free_all(hash);
return NULL;
}
/*
* 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
* [out] hash: message digest BIO
* [in] outdata: outdata file BIO
* [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);
PKCS7_free(ctx->cat_ctx->p7);
OPENSSL_free(ctx->cat_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.
* [in] indata: mapped CAT file (unused)
* [in] filesize: size of CAT file
* Verify mapped PKCS#7 (CAT) file and create CAT format specific structure.
* [in] indata: mapped file
* [in] filesize: size of file
* [returns] pointer to CAT format specific structure
*/
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize)
{
CAT_CTX *cat_ctx;
PKCS7 *p7;
/* squash the unused parameter warning */
(void)indata;
p7 = pkcs7_read_data(indata, filesize);
if (!p7)
return NULL; /* FAILED */
if (!PKCS7_type_is_signed(p7)) {
PKCS7_free(p7);
return NULL; /* FAILED */
}
cat_ctx = OPENSSL_zalloc(sizeof(CAT_CTX));
cat_ctx->p7 = p7;
cat_ctx->sigpos = 0;
cat_ctx->siglen = filesize;
cat_ctx->fileend = filesize;
return cat_ctx; /* OK */
}
/*
* Add "1.3.6.1.4.1.311.10.1" MS_CTL_OBJID signed attribute
* [in, out] p7: new PKCS#7 signature
* [returns] 0 on error or 1 on success
*/
static int cat_add_ms_ctl_object(PKCS7 *p7)
{
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
PKCS7_SIGNER_INFO *si;
signer_info = PKCS7_get_signer_info(p7);
if (!signer_info)
return 0; /* FAILED */
si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0);
if (!si)
return 0; /* FAILED */
if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
V_ASN1_OBJECT, OBJ_txt2obj(MS_CTL_OBJID, 1)))
return 0; /* FAILED */
return 1; /* OK */
}
/*
* Sign the MS CTL blob.
* Certificate Trust List (CTL) is a list of file names or thumbprints.
* All the items in this list are authenticated (approved) by the signing entity.
* [in, out] p7: new PKCS#7 signature
* [in] contents: Certificate Trust List (CTL)
* [returns] 0 on error or 1 on success
*/
static int cat_sign_ms_ctl_content(PKCS7 *p7, PKCS7 *contents)
{
u_char *content;
int seqhdrlen, content_length;
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:
c-basic-offset: 4

View File

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

608
helpers.c
View File

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

451
msi.c
View File

@ -100,30 +100,6 @@ static const u_char msi_zeroes[] = {
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 {
u_char signature[8]; /* 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 */
u_char unused_clsid[16]; /* reserved and unused */
@ -215,44 +191,50 @@ struct msi_ctx_st {
/* FILE_FORMAT method prototypes */
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 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_check_file(FILE_FORMAT_CTX *ctx, int detached);
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 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 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 BIO *msi_bio_free(BIO *hash, BIO *outdata);
static void msi_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static void msi_bio_free(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 = {
.ctx_new = msi_ctx_new,
.data_blob_get = msi_spc_sip_info_get,
.pkcs7_contents_get = msi_pkcs7_contents_get,
.hash_length_get = msi_hash_length_get,
.check_file = msi_check_file,
.digest_calc = msi_digest_calc,
.verify_digests = msi_verify_digests,
.pkcs7_extract = msi_pkcs7_extract,
.pkcs7_extract_to_nest = msi_pkcs7_extract_to_nest,
.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,
.bio_free = msi_bio_free,
.ctx_cleanup = msi_ctx_cleanup
.ctx_cleanup = msi_ctx_cleanup,
.is_detaching_supported = msi_is_detaching_supported
};
/* Prototypes */
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,
char **p, uint32_t len);
static PKCS7 *msi_pkcs7_get_digital_signature(FILE_FORMAT_CTX *ctx, MSI_ENTRY *ds);
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,
u_char *p_msiex, uint32_t len_msiex, BIO *outdata);
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_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_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 MSI_ENTRY *msi_root_entry_get(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 void msi_dirent_free(MSI_DIRENT *dirent);
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
@ -290,12 +273,12 @@ static FILE_FORMAT_CTX *msi_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
return NULL; /* FAILED */
}
if (memcmp(options->indata, msi_magic, sizeof msi_magic)) {
unmap_file(options->infile, filesize);
unmap_file(options->indata, filesize);
return NULL; /* FAILED */
}
msi_ctx = msi_ctx_get(options->indata, filesize);
if (!msi_ctx) {
unmap_file(options->infile, filesize);
unmap_file(options->indata, filesize);
return NULL; /* FAILED */
}
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.
* 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] plen: SpcSipInfo data length
* [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)
{
const u_char msistr[] = {
const u_char SpcUUIDSipInfoMsi[] = {
0xf1, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
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->e, 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);
*p = OPENSSL_malloc((size_t)*plen);
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
* [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;
/*
* Get DigitalSignature and MsiDigitalSignatureEx streams,
* 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, use initialized message digest BIO */
(void)md;
/* squash the unused parameter warning */
(void)detached;
if (!ctx) {
printf("Init error\n\n");
return 0; /* FAILED */
if (ctx->options->add_msi_dse && !msi_calc_MsiDigitalSignatureEx(ctx, hash)) {
printf("Unable to calc MsiDigitalSignatureEx\n");
return NULL; /* FAILED */
}
if (detached) {
printf("Checking the specified catalog file\n\n");
return 1; /* OK */
if (!msi_hash_dir(ctx->msi_ctx->msi, ctx->msi_ctx->dirent, hash, 1)) {
printf("Unable to msi_handle_dir()\n");
return NULL; /* 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 */
content = spc_indirect_data_content_get(hash, ctx);
return pkcs7_set_content(content);
}
/*
@ -554,21 +496,54 @@ static int msi_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
static PKCS7 *msi_pkcs7_extract(FILE_FORMAT_CTX *ctx)
{
PKCS7 *p7;
uint32_t len;
char *p;
MSI_ENTRY *ds;
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) {
printf("MSI file has no signature\n");
return NULL; /* FAILED */
}
len = GET_UINT32_LE(ds->size);
if (len == 0 || len >= MAXREGSECT) {
printf("Corrupted DigitalSignature stream length 0x%08X\n", len);
p7 = msi_pkcs7_get_digital_signature(ctx, ds);
if (!p7) {
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 */
}
p = OPENSSL_malloc((size_t)len);
p7 = msi_pkcs7_get_digital_signature(ctx, ds, &p, len);
OPENSSL_free(p);
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)
{
MSI_ENTRY *ds;
/* squash the unused parameter warning */
(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,
sizeof digital_signature_ex)) {
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
* [out] hash: message digest BIO
* [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 */
(void)outdata;
if (ctx->options->add_msi_dse && !msi_calc_MsiDigitalSignatureEx(ctx, hash)) {
printf("Unable to calc MsiDigitalSignatureEx\n");
hash = msi_digest_calc_bio(ctx, hash);
if (!hash) {
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 *msi_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 (!msi_hash_dir(ctx->msi_ctx->msi, ctx->msi_ctx->dirent, hash, 1)) {
printf("Unable to msi_handle_dir()\n");
if (!add_indirect_data_object(p7)) {
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
PKCS7_free(p7);
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)
|| ctx->options->cmd == CMD_ADD) {
MSI_ENTRY *dse = NULL;
MSI_ENTRY *ds = msi_signatures_get(ctx->msi_ctx->dirent, &dse);
if (!ds) {
printf("MSI file has no signature\n\n");
return NULL; /* FAILED */
}
if (!msi_check_MsiDigitalSignatureEx(ctx, dse)) {
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;
content = spc_indirect_data_content_get(hash, ctx);
if (!content) {
printf("Failed to get spcIndirectDataContent\n");
return NULL; /* FAILED */
}
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) {
printf("Creating a new signature failed\n");
return NULL; /* FAILED */
}
if (!add_indirect_data_object(p7, hash, ctx)) {
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
if (!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 */
}
if (ctx->options->nest)
ctx->options->prevsig = cursig;
ASN1_OCTET_STRING_free(content);
return p7;
}
@ -715,34 +671,22 @@ static int msi_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
* [out] outdata: outdata file BIO
* [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(outdata);
return NULL;
}
/*
* 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
* [out] hash: message digest BIO
* [out] outdata: outdata file BIO
* [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);
msi_file_free(ctx->msi_ctx->msi);
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);
}
static int msi_is_detaching_supported(void)
{
return 1; /* OK */
}
/*
* MSI helper functions
*/
@ -791,18 +740,26 @@ static MSI_CTX *msi_ctx_get(char *indata, uint32_t filesize)
return msi_ctx; /* OK */
}
static PKCS7 *msi_pkcs7_get_digital_signature(FILE_FORMAT_CTX *ctx, MSI_ENTRY *ds,
char **p, uint32_t len)
static PKCS7 *msi_pkcs7_get_digital_signature(FILE_FORMAT_CTX *ctx, MSI_ENTRY *ds)
{
PKCS7 *p7 = NULL;
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");
OPENSSL_free(p);
return NULL;
}
blob = (u_char *)*p;
blob = (u_char *)p;
p7 = d2i_PKCS7(NULL, &blob, len);
OPENSSL_free(p);
if (!p7) {
printf("Failed to extract PKCS7 data\n");
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 */
inlen = stream_read(msi, child->entry, p_msi, len_msi, p_msiex, len_msiex, &indata, inlen, is_root);
if (inlen == 0) {
printf("Failed to read stream data\n");
OPENSSL_free(indata);
continue;
continue; /* skip a null stream */
}
/* set the size of the user-defined data if this is a stream object */
PUT_UINT32_LE(inlen, buf);
@ -2179,6 +2135,25 @@ out:
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
* 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
* 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
* of being merely a file content hash (as what is output by the
* 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");
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->len_msiex = (uint32_t)BIO_gets(prehash,
(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
* 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)) {
printf("Unable to add nested signature with a different MD type (-h parameter) "
"than what exists in the MSI file already.\nThis is due to the presence of "
"MsiDigitalSignatureEx (-add-msi-dse parameter).\n\n");
X509_ALGOR *alg;
const ASN1_OBJECT *aoid;
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 */
}
if (!dse && ctx->options->add_msi_dse) {
printf("Unable to add signature with -add-msi-dse parameter "
"without breaking the initial signature.\n\n");
printf("It is not possible to add a nested signature using the -add-msi-dse parameter "
"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 */
}
if (dse && !ctx->options->add_msi_dse) {
printf("Unable to add signature without -add-msi-dse parameter "
"without breaking the initial signature.\nThis is due to the presence of "
"MsiDigitalSignatureEx (-add-msi-dse parameter).\n"
"Should use -add-msi-dse options in this case.\n\n");
printf("It is not possible to add a signature without using the -add-msi-dse parameter, "
"as doing so would invalidate the initial signature due to the presence of MsiDigitalSignatureEx.\n"
"In this case, consider using the -add-msi-dse option.\n");
return 0; /* FAILED */
}
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:
c-basic-offset: 4

File diff suppressed because it is too large Load Diff

View File

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

399
pe.c
View File

@ -44,34 +44,40 @@ struct pe_ctx_st {
/* FILE_FORMAT method prototypes */
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 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_check_file(FILE_FORMAT_CTX *ctx, int detached);
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_indirect_data(FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOptionalValue *obj);
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 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 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_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static void pe_bio_free(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 = {
.ctx_new = pe_ctx_new,
.data_blob_get = pe_spc_image_data_get,
.pkcs7_contents_get = pe_pkcs7_contents_get,
.hash_length_get = pe_hash_length_get,
.check_file = pe_check_file,
.digest_calc = pe_digest_calc,
.verify_digests = pe_verify_digests,
.verify_indirect_data = pe_verify_indirect_data,
.pkcs7_extract = pe_pkcs7_extract,
.pkcs7_extract_to_nest = pe_pkcs7_extract_to_nest,
.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,
.update_data_size = pe_update_data_size,
.bio_free = pe_bio_free,
.ctx_cleanup = pe_ctx_cleanup
.ctx_cleanup = pe_ctx_cleanup,
.is_detaching_supported = pe_is_detaching_supported
};
/* 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_realchecksum(FILE_FORMAT_CTX *ctx);
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 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 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 */
}
if (memcmp(options->indata, "MZ", 2)) {
unmap_file(options->infile, filesize);
unmap_file(options->indata, filesize);
return NULL; /* FAILED */
}
pe_ctx = pe_ctx_get(options->indata, filesize);
if (!pe_ctx) {
unmap_file(options->infile, filesize);
unmap_file(options->indata, filesize);
return NULL; /* FAILED */
}
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 */
}
/*
* 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
* [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,
* 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.
* Returns 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] pointer to calculated message digest
*/
static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
{
size_t written;
uint32_t idx = 0, fileend;
u_char *mdbuf = NULL;
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);
}
}
u_char *mdbuf;
BIO *bhash = pe_digest_calc_bio(ctx, md);
if (!bhash) {
return 0; /* FAILED */
}
mdbuf = OPENSSL_malloc((size_t)EVP_MD_size(md));
BIO_gets(bhash, (char*)mdbuf, EVP_MD_size(md));
BIO_free_all(bhash);
return mdbuf; /* OK */
return mdbuf; /* OK */
}
/*
* Calculate message digest and page_hash and compare to values retrieved
* 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)
{
if (ctx->pe_ctx->sigpos == 0 || ctx->pe_ctx->siglen == 0
|| ctx->pe_ctx->sigpos > ctx->pe_ctx->fileend) {
if (!pe_check_file(ctx)) {
return NULL; /* FAILED */
}
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.
* [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)
{
if (ctx->pe_ctx->sigpos == 0) {
printf("PE file does not have any signature\n");
return 1; /* FAILED */
if (!pe_check_file(ctx)) {
return 1; /* FAILED, no signature */
}
/* Strip current signature */
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
* [out] hash: message digest 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) {
/* Strip current signature */
ctx->pe_ctx->fileend = ctx->pe_ctx->sigpos;
}
if (!pe_modify_header(ctx, hash, outdata)) {
printf("Unable to modify file header\n");
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 *pe_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 (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) {
printf("Creating a new signature failed\n");
return NULL; /* FAILED */
}
if (!add_indirect_data_object(p7, hash, ctx)) {
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
if (!add_indirect_data_object(p7)) {
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
if (ctx->options->nest)
ctx->options->prevsig = cursig;
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;
}
@ -555,40 +496,33 @@ static void pe_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
* [out] outdata: outdata file BIO (unused)
* [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 */
(void)outdata;
BIO_free_all(hash);
return NULL;
}
/*
* 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] hash: message digest BIO
* [in] outdata: outdata file BIO
* [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);
OPENSSL_free(ctx->pe_ctx);
OPENSSL_free(ctx);
}
static int pe_is_detaching_supported(void)
{
return 1; /* OK */
}
/*
* 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);
/* Since fix for MS Bulletin MS12-024 we can really assume
that signature should be last part of file */
if ((sigpos > 0 && sigpos < filesize && sigpos + siglen != filesize)
|| (sigpos >= filesize)) {
printf("Corrupt PE file - current signature not at the end of the file\n");
return NULL; /* FAILED */
}
if ((sigpos > 0 && siglen == 0) || (sigpos == 0 && siglen > 0)) {
printf("Corrupt signature\n");
return NULL; /* FAILED */
if ((sigpos != 0 || siglen != 0) &&
(sigpos == 0 || siglen == 0 || sigpos >= filesize || sigpos + siglen != filesize)) {
printf("Ignoring PE signature not at the end of the file\n");
sigpos = 0;
siglen = 0;
}
pe_ctx = OPENSSL_zalloc(sizeof(PE_CTX));
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 */
}
/*
* 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
*/
@ -1172,6 +1159,58 @@ static SpcLink *pe_page_hash_link_get(FILE_FORMAT_CTX *ctx, int phtype)
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:
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-----
MIIDoTCCAomgAwIBAgIUfuEVHNA/1VLDJI9mhANrBndIj6swDQYJKoZIhvcNAQEL
MIIDoTCCAomgAwIBAgIUVD6Q+gnrOmJWbEnmfydpUg2JNmswDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTcwMTAxMDAwMDAwWhcNMjYxMTEwMDAwMDAwWjBYMQswCQYDVQQGEwJQTDEVMBMG
MTcwMTAxMDAwMDAwWhcNMzYxMjI3MDAwMDAwWjBYMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEQMA4GA1UEAwwHUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAMRykK9mZCSpkVUbCq1r12OXvIDkcjj+g4JpyZOrmPpz5RvmLvYBBgeV
IsUcqHm3/uSLpOFu/pwFJ2CBZVPJ1d49Y9DVnNR1dUbneWX9tE7A6NV9IG1kVagM
veI/ANLuRi0H51aAZS9L8c6WxlR4+pxJoCZp1tyTGmfjxzBEXUWvyUrIMrW/r9TH
u5gGgR6k86EbH7q71XRLhLeEi9QGCG24gobngYNZa5mb8DgLCkUeFtRsrYGEUT0G
HTpAGXUrpAb3U7+4LkGaS6mc0NPTW4lz06Z3VhyYwwAbgU2DZQjMpqYWv6UctOP+
5elPDc/PrTAdHAgbOhgvt1HUlqgn7lUCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUWIpzlJI+vefcJwcNGHwwRms/2ncwHwYDVR0jBBgwFoAUWIpz
lJI+vefcJwcNGHwwRms/2ncwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUA
A4IBAQAl+G1nXXW5u3notmAG5y8kwufFqNi5Jn1HVbT08w4IiteWMw3D9GEOCueM
g5A03bC/Xv1PRvMatXQSARRvvVl3y1l98sA+97SP/FFUla3W5Rn91OsWd4qkcXhv
CtPKHpz0SCjKLv3HG/C7fBJPG9XHMgkGZarM2KsQUlkn7DjdBccYcp/zJvtvm+be
nR5ZqE6LI52WCXg0w/KlJlildU5LE/bvHbfmRUVm/4GhUNN8ko8eG67ueuftkeTD
banKmnuSay02I42A0th2w8Hz7oaOUEpl8S9TfqeFuqLhtUP0FzUNMPAg0o5YTpe4
xAArbPbFvH2l3plEaYccKYvbAGT/
AQoCggEBAMUvCAWI9LrgtVw9RARZLFb/qB1868H86eyr8oITzXl6u9FSQwvGH1MG
szRhuD9TJAjy1uIiVPJ7ez2VjKXm2G9lUZMPJQRt50XTGbsGGDi4ITU1W3P+HI5u
45I0IL14Qv/R8X26lndBzlY4ImoCTAN4KzdfvoGLaMpNvbC1P7a4mlukrumi3WKT
RAq46Mj5DAqr63NOolWimtTB+h0ZWv+xxngR7cfo+EimvhPB7y3xhY9OJ/27l6mJ
uQJohz5PmzhZByluMhicTsd2cJEKQb7jnih492okCj6vH/FJmKg+DzXKTyue5Ki4
2jhzM9v1npyIkd7s/gnZVEsHH6oQIt8CAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUGjxG/vql0oJgItr7HsLaW+koiMgwHwYDVR0jBBgwFoAUGjxG
/vql0oJgItr7HsLaW+koiMgwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUA
A4IBAQAy7AKbO8B8Njseqjy2LAj2sKHCLc1jsQa7izOAtr852NYFAfpBvkqQfxne
8k5iPKmcJE+Sm4wv3V/lzx2AHEXAPa7BgiAo7yeo9UbrDgRRGw4MirQ/djp44ekv
KCc54bSE/paUZyEWKr8NbdBy7SZfZ/Dd+XUY2lbm3Mue3AzWl4xp4StoT6oaw6VI
H6bIhZupond/RWp4jmHHEfvl4T6YLzl5FC+Ec2xBbpk5vAVZgyfrlv+W6V/il/X9
KTZl5ax4FJAm7vPn6fsgdAM5y24zJUAkeakKFsBYtoVoGg1iiFuMEGwFRn7EZYl1
8D16qEH+YPLCzujH1PhzjmmAfKl2
-----END CERTIFICATE-----

Binary file not shown.

View File

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

View File

@ -2,13 +2,13 @@
MIICMzCCARsCAQEwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UEBhMCUEwxFTATBgNV
BAoMDG9zc2xzaWduY29kZTEgMB4GA1UECwwXQ2VydGlmaWNhdGlvbiBBdXRob3Jp
dHkxHzAdBgNVBAMMFkludGVybWVkaWF0ZSBDQSBDUkwgRFAXDTE5MDEwMTAwMDAw
MFoXDTQzMDEwMTAwMDAwMFowTjAlAhQxdzwUXgMSEn/RzOwbdKtxlLgYJhcNMjMw
NDI4MTIzMzQwWjAlAhRJcBo95Rq1+F4NMWjvsucwEeDJ4xcNMjMwNDI4MTIzMzM5
WqAwMC4wHwYDVR0jBBgwFoAUYbtAOknHjmiu3l8ONAUY387kFi8wCwYDVR0UBAQC
AhACMA0GCSqGSIb3DQEBCwUAA4IBAQBOPbjiBQ1jOEjfQ1Q3/DBfzFKxeL7Cdoiq
6l1psqamZRTmU0a+1qRH/qokB0gA1XeeYIZRcruthHDk87F+WZPCKIr5cqfH2RFA
xjDEkwgA8OZSdSMh+ZhBLBoGjZhFdnX/FknMcA23cLnzuv4RmsbiokwWrysebDNY
DbTQpa/OFvqmHmgXbhrBqUinF7gl1ppzXs/d+FjSg1aAre/lx3KEXCgc126kldS9
9+c//UPmltYB17ipVWBmVOyVHNphnHtqPElD9Gz1DooVZ1opsqRBh0APu7fqmm6A
5d/lvNlPrlu835/fgUF3YmyU+w4x5sQCBjprTD6QIbIzCXDXfpBj
MFoXDTQzMDEwMTAwMDAwMFowTjAlAhQcZvYIe2b1FreAKfoi/uGkSGJCthcNMjQw
MjI3MTUzMDE0WjAlAhRrNutWBthv4g3zTdSYklrQM8dCwBcNMjQwMjI3MTUzMDE0
WqAwMC4wHwYDVR0jBBgwFoAUFDxiqeJxiJbmZ4erKH0pBIhq7SMwCwYDVR0UBAQC
AhACMA0GCSqGSIb3DQEBCwUAA4IBAQBZzGXEP4XdKuJ8ANIBGPu1Z+7T+4ln+nu3
MEPC9BexVAA02YPZx6i4c3cHC87aOL7zsr/K9OeF5MAYzi2QJwsenF4b9QL2rzQV
sCAb3sY5ImAxN38GTJ+oI+uTeOefNE0wS7pP4phRmYNZwyDhxA2iT76+luoygyth
NesiGalMFDrJvUM1DADTZGQrz9cQVgFq9WTcta9rdTYqSNctxkbpQaY0hgssH1Sh
hWlSiFttciA2XVD7Ju/Qv9zN4nCQC0LskgKhqsefsOukpo6jqJ92OmNrrNaERfqs
Yavzuj6DlcnE46ZxA0y2Du1apz0WDlbcAnsEqfNSDDCid09v+V9a
-----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-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDhMfTdugKYNDCN
opsz9rTpYF710kq3fDN3JdmEFPoZfhZ58CBm+iZBJRCc8KoXMbKAgAZsFaUyU63M
07fYIxJeu3CTOi7kFQRy5bfGrEOnTBMKUqR+KcOZNeNYtfkv4eca25AtTyziJeBV
TOqDoVG5x75ad0+Ab4xA9bhbN4+7m5jS1aJeHtj8eDBkJOIOKGbZ0WEstffAIzWO
qCC+YFqxsXLO2hOxRgxgpsY9Va4bynn6HW0FZUcUQGEDH0Y17o2KInSyYASad7VI
F5jjiJnAzzvU701URZ7kjJFGbT9W7523Ljytl/Mvg+5qTG5JNQjVDsWHte6j1Kq8
bAHpZ6NjAgMBAAECggEBAKDpXmv1FxeE61C5aSc3WMwNxaznZ+Y2RFwV2phrmM4Q
b6UP9Uc/5YfVIUrTGObb5w207WHcEZ+ldWIPwqUZYm34h5dcEtd9QSGMjcXTn7/y
NwTASrOvygk3HU1tMjKJu+ZQD3Sgx5SMtgCdplEKO2iBlr3z1QYULubX7bSYPgcx
7sOOpEpITayd8HdOkqkqUvLKxAW5xhL2AzBQHaJiGL/zaW0uKEoOVuTrhNw4+Lnw
2IYGrdXpGLAd6hno4kOg2ZkJKWA4Yd+adroeV3BjJ2G1hLJAbPDtS/uB4ZnT1zQx
OlkqiPgnoH+16I+aLOs7MvIwQ7VRdF46Exk/9qIdHEECgYEA/sUoOQya1/JgPpbd
QeAViTvu9vCFJCnJMkyobG/CVHRDIsNwE/CpaQE+vCn/LpUeKD1KCHIjTOvLF4HM
CHt9SECApJESIdexKGP6DVoW+xnomojN/k0YW1JkrnXqmvDw5u/nvFz/JPncKZzB
+Ahx6ocORz+t10V8IRn6SlN0E4MCgYEA4khANwZ0Ys0CwVJkx5+mX3ukgXGsLDcB
p1bGrnXhbZOiZxxeWjbR/7b4PyAzsoqxiC/F3RGnU5TEPGnUUeGWv8UFsVsgd8tG
QvTOC5iEio6fs/IPZK4Asy4a5ByX6bXjbqSnypN+vf+9lFOvI/+yZ9zKejdoD5Xw
k150XRhWyqECfzDDi+9fekPbIJDaT39MZNLfpd2eK93AIcJ+6b3XplqD5lXBErK+
Xa67jkZ1w2InKJ6LHKCBOECA4V6eeW8mM9Sgg/77xXy0zDPu7u2fUMa/LsZlaQhD
uWXBX4QFDeKaO4H4aWKkajGpoXpVhsry0tsQ/qqkhaGuqxOq5T1Uu+MCgYEAhz2J
a5mm+9ntmJ9m7kxDwnOCWX8X2QEzMtFRQ7nedoAzIw84cRCsp/myGwBjBYWRH4T1
6+9+Ix0Zv8W8iQeb8peNlHeTSyWpo6DueM26AZnGZ2T3wEOi1XRrzAQu4xa7jEhK
pG9M47+yjbEKTyimdx7lwO/WeOIze9CLGYzPaqECgYBfgaE2HpG0SYKfDy0ipyxe
p5ZoGQUXksi7WHSWSTl3tA/0NTtYKCHKb1/hRezjmdRgTuqBaV3y2nF1XmlKw9EX
nYx/xAfhnyh9K7EZEMtDP2zL6tV1sp6b4Jd7sbFvM/bMJBY6KtKx59Y0u4nkgcH2
gt3jad7Axl6C3faOfjzeyw==
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCplbeNvGrZmTDz
p48TyvpOX36bGPMfyTVc8ZfAoh0SG86EFc1LHBV2K52dshHYqniQ6lE14jhsRPps
YRBUFXO7I84Jd5CVcrvBWGuL8wXxjMwIW5buzY4x5oKowlyQGIasNiC8Mgx8TncJ
kVWE6ekgoP4i1f4PVsFyG8zVNpI5VzHArAemYhvDjuA5jgTisfP8ph2pxUKTzYAI
SaKm2YkBFvyhhTxtqnXHt8S0NnfDSCedKSzl1caN1TAKSbWoeChb+Tq8rycjPXh/
/7TkYgxmlSHiQhRcyEaZs54Ud8Q0nsnfRMhEtewr2IACmuKrFnoS+GtY5glPilR5
ScZ+7A9TAgMBAAECggEABOI/XIzFYMzeg2Rg8DAquQlyc92NE5zPtW0/WxhhizdT
bPF3EISXh9DdMimCBeH8XxIzWFfSeFaoNFHp1GCf9ckYRuptk8ppz3OKVhOIbxqr
YNY9UVVCrEFmjJ0Vxj7Be5M9TTEU4mxLVX4FtmDVClubeOxyX/oqcr4uwme0Az6A
tjBVzl+YEYvZrbhao5d09LVQ3zj1T1EQ+XU5iTTV5Two86FQ6NQ9txe7jxcB8x8S
BbD/PakmZj+oIdVBp4xnrhCJ3mYdzXy3qHWxq/BtHgS5fY3/tq3xtVSNxw7QJG7j
CT2Cps3/99Lq2CPi8OkQKgjJwWqCZ0jOwHahEMlWIQKBgQDneq4LH0zfPJIW2zsi
C7U813hV4NuQXd5EW2bmNe4KKnlrcbt3ZtJv8v3Ff5lMm1i8jDCeaeGhZOi/Ag/z
aTtM1STFFEQg3QktcSAvS7hXufvAeufSrPOZdpBO51wqZl5wLMp2lsq885R3wnRl
FtIErdmsLigVMC8RZ++gFNIjMQKBgQC7jJE93wV3j36QA7NAgxNH0AW5p5foWuA8
gR8MA9cpFI7X7q6hW9HYXw30kD3IzN6UW4U5LT4Pandxx484G1KENcyW2TzeGtpC
MWBWHF4Mbxb/2pEkQoPk1dZmUxF5hvaGGHQYJn/pnJFavGUoNBlNjaIfgStzd1IO
68ceo5URwwKBgGjHJjrQmzo9L5968sRRamM04Tp2QsyRQMfOW8B+ztX5LebNn17H
wx97bRVV0a1UcBFAn81E/iXRCG1VYKT8kCQSIse2ibQaeUoBd+EQtEu5WtRgjcjW
Epn3ihC9NwHWPo8mJysQzIpE84JWGducPcpyayI97lTQ761AT741Tn0xAoGARtG2
ioFrhBEoPmNXTZXxMt3HO6qgPvoJ0G8FdTkCBx4fLkSPppiQbb6++0l4Oxm5NpY0
gTmnRJT0U3+CgjI2/3t9LL0NMeU742DXusxtaw6LxcMXqXSAb2mb0vmtEJG5Bzu2
ouPuyxz2+idHn13E7Db+MB1Ldgdpcf7wKo6knJcCgYBwbcjW0MwCah3w4N4VLXBX
Q5wPSw7cRcytHqrrWkT/nTI3fxwd7UW6ZdM0IwGIAwYgBYD5B78KH0aP6BlUmYWu
8vut6S/MsNyCzHQVbcR9BUK3drByzhysVE3TUQKjCA33v6M/tTixhpyPf+ZZtjlK
b1+6D1aGpwt+11f9ubd+Nw==
-----END PRIVATE KEY-----

View File

@ -1,25 +1,25 @@
-----BEGIN CERTIFICATE-----
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
JVHLUWz0r6IIp0mHrMwoI94yZBVXje0=
BQADggEBAAhzijhC1kvBV75rxRqj27gtYRG8dNkHc5umzwXyNNMn2tI/kO2Rf+ES
9RamQE9sfvOgg3UqfXIfRPsC4cBHnjT+ELdqbt4byk3LPtstJGFuLy0iNRNY9f1j
lBJrldLZNNsIpNMQa0u5h/z4m0CAA8j6ayUvcoR11y2zYHkHlSScTq/s7gSQzXlK
z4DRiiYif2OEdKVeRCqlDV8AOlhm1+9am74dkfO71aT0G2hko2u19NWZvjc/DqI1
V+e2g5TDE7V65d9vvf9tA26i0At/VazvnhsgdpgUkwS6mjUvx+gW3i5YJhtXjdAX
hpE0ajpKT0x/dNa/qCwl/9zc8XxGnPk=
-----END CERTIFICATE-----

View File

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

Binary file not shown.

View File

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

View File

@ -1,28 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDPPtqTsdzCK99B
5zSNIiu429Tbc/S4Aa9eSsbjcefTy7NkCPankl8QeBIvQ75P98qH828iDlSH2u3N
Rp121r9wjEaM3qmkkyP0oWwjoK0du6y3hI59rHhOt3FqO0ec40Rf1yxrCKE+pCMd
TI+Ifozlxe/T7FhwxLjOIBIt4gDF6sOn06ToTC1CoVi/nd9E5vgKjuQW0F1Y7Hey
Ft64YStUXxvLB03mw8+bciZI3BQGrgOD9CCTWZVK7OO147qc8TEoQle1xKISM5wh
vaHbNUuhMRJG4qVyrZ54BICRW7r5cJZBBDVc5i1XD50Nup4wIjJtBAnPZDAwEwac
XZ53hHAPAgMBAAECggEAeGmume3XtEHFYAcz82SNPsULcc53u4nPGNwdnv0Jk3dh
bZf/p/FVpr384tVbeB8i38bDJWhqGN1NGd4Tk37GkGAQhbzBmEudsn8v06uBqirm
+WHdYIubAzF2hiCXRUKO8ZiVyEKlXT4E4Psg0k+lEcPlyp4h7LOAJNNhfKM5i8QF
3K7Pp/VcFqtwJSmu0vSycJOJWyUfqRLxgWS95r2EG1rwD46KFBCoHOa50kiZFdiI
q2h1XOiXtdaG1yn6HRS75gV4CR+MCGkczs9onSl4IpwNlq595NMCujhFcHjjKzwV
F4E/83ehtj7WruyNFwrFbabNAvLSY8nVBHabn/3L4QKBgQDrYHKn0njihjbaPT5v
1yoJyz/1eX/fscvDhQFvhQoirk/A3iSwOd1jszGvvYxRnfRnLDOszTCq/+CRSv09
sU7ECDcJPFJY8GzDMLjoBJRDtHdsFjU6tliHgyXFVpu46sIt0Z03Wglowyytc9ws
9e5uf3xolNbhdLTWfovoRp5LJwKBgQDhZ2qWOyGkVyuPn0GSVJVnOgK/PUd9b7Ze
R77i/P6sgp9d3eAXK46oYJM+6TPnQwZYE9CHUMMqHmtCm2iHqCEitZ9mvZgPt6p+
sR8HxJ/JAowDB8mOQ8usd/1S0M5e8SwSpuRajkYw0cndvwn+ezAlKsZyCN6sm73B
3ruQvVjk2QKBgAJG6pUJCjZWyg0Obp4yXKu/lZzQUhZd5/S6QqtLhC+VtBvPildS
F/ww7Zgfo03e01B0MwPG8GOXGhsNuKlyH6rx0WZ7eOh3WvYAcKl98dk907Ht/RHW
VcDp2eGw1szRKJO85WJ1soWa7cG3zzd4IZhcD14LopCHyoAQtVXH6RwdAoGAddQM
yNnCXVlgIST8LxVeQGb31qae/3htWd2hcKEWNHHYA0agBRy051oMvv9DLapA37wD
7yiNzS+3nEsHGpsOL0nIOPn1SooVa0MF2Ja1fGuDa3Yfq+nOx6q11xvmNYVXJ6zs
hFYJZS3Vm8Bo5gnZgiRZNnViidKkIHthi2kf1gkCgYBzaNgT4fbNPpgia/Vz3rd9
UIYpVzMEP6HkTVYXQH+qLzRpjl4HG6LanMbxtf/0MBHBwtEyVftKopgvkcJCDUCS
Ls+BYieF547/2W+pnV7lbz7eD6w2o7zNPNj/l+RB2PXgBZGQv1N4HgLsz+yk7eyI
s3UnnC/9NhgSMwB82OPX3g==
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDxU8lwCceWEesm
HIQu9M8mIznHFWmxFF55E16DseWr1K2FbOKnNv1ddNhUHFhBQChcGPn/CvwfOMR7
DbCETrty9HUtoK3fCVZQuYIjZwRLZZB2ryLgO4PK+j07Z61yABi7NKBKv8oHISLU
QcNg7rBAZhmAurKpNu2Gpz/jFpFXwd6O+8xnsYFLT0zyjrq0rEvLmWQd5FBQaVt7
P+U9GH3GCg0kmdhIXAfdfSnqzj0OMnnzVdnEYrd1mYx+ZA7m0CmVJw330QXWiyax
wimNHUvlpIiZA8ol17tAybinhPL5nSM/LRZ2PN90EgyX1bv3x/cKCEiOYPSZ7xXV
mrRGjCtjAgMBAAECggEAHj01fIh9LdzI7lmcZpXebxTy5HNWbw3yWJGIwk/ES6e2
poViUTmevdsqUD/M/0AezouCp+akePUQCatJdwq2ikz/cdw0bUIqQqs8F1uNOjVb
yMNhR1+tv/1jNtJi9Wn1r1+ExlkJ46LPTnF/HeJKy4b/oxXB1VpAoSLL6pSlWa1+
+iEWM+s6xlxyFkeWPq3L3u1QGkuW58KqQae86mR8Mgc0kOVuTCqWpHgNjfxt7tnt
L/oBE9zEJmS3iZcGh1X5VR4CUQmtrCp7ldNdhSNk5WcNCNSsuIX+B13s658a0sRB
AnPIX08moB5VHZ/danblny5Zo6SrobWBBcTabwjnYQKBgQD/BHktS70tQj3yBqVL
xXmaO5ozqMLqF9A2o4EiJ/pF07ecHXmbiGaP9Nf/FJemuU5OHjw8akuxKn2M+DTu
gHYOHwByA9/SOeAiD8bp/dJNE+2BO2zygoG/adhEV5tLK8IYdz241t8oVZbQLwql
ZCs1uFab6E/cZEJgSQ0QuC8vtwKBgQDyQc+MX56UFFCP1QpWLIwFVdoPbOj/3cVZ
FIjQO9rNYNIscS36nISIBh0voubI2xFvO7/s+WS1pD1bOmn6qwsndewFGdmMtjnN
YguakmHAUmcF33f+gXVzwR91QvGPTjI2Fzd59OwOrZofO1+hajQiBKIP2B9VHJNP
khspe44JtQKBgFqTTyrMZNOnXHMS8zC3Ydpq4vkILrqQXK6bYiksg9K7QNKdEW0x
hCQLNZBu0vIvjOVoDcLzihDR46fnHH29eLDJSBI22A9F6RqP+flv4nrn4gptfeOg
gM7onByh9RE86IJiD7UP9FDSHW+x1Zkqu8Inx/M2Du9bWMv0BkTy9id/AoGBAOEy
oDcDZCyPPdyW1AcLXhZPmmegfG/tvlhyqEO6gElO6dF6XJ2NBf5UgKkZq6OnUWuv
hVhK9X2M8aRuhroIalQCYKbVQtB1TQJJVDQaQ1g+wZpKBAfIXGCAdDfTRS5MKIzz
xBRQw2dZpd3Gmb05NsEwwV4tL+M0rxPW4/0J6B3JAoGAB1vlzPsfKVvV9jwVpfdO
W2MWAqPF4iI716zLt2F30WNe/42MudQGvMYUEPTYQMu3hhpQk/6UFY2Mfux6+OKk
zG1khRdlq9BkCczfSVjkUvf4wTUUY5b66i4EpeJ//8OArZEx67LhmW715h/LExzG
jkdwUMLiaSrpf8KSTL3NxM0=
-----END PRIVATE KEY-----

View File

@ -1,25 +1,25 @@
-----BEGIN CERTIFICATE-----
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
8e7rP/mN
AAAAAAAAAAAAAAAAAAAAAAAAMA0GCSqGSIb3DQEBCwUAA4IBAQBMiBltqGRRLmK9
0RymCJ4oxmX2jwZ4SM7fem39Ozei7NIQIw5nlkPJ7ZWyfQQNFMIujfwJJGzDguax
mMJHWngzbKjkbdSHnQswxT79RRwenlIKkExck6p2OUT82nGu/6TBIYutMJlITwKF
5OEmu+WneCvTkvEs0wussIug7E7dV6jJO9/TbwWyrtqU/t9GNRbu/4FIdQ9p9pK9
BcqaPmjn7IqnLs94THFfMFH0HVkqpLOfa9Wa8uc/C7WyIMTkchXb4U7/8B/hsDj7
BfKwN/F+IMNw4Rfqytk2JSWuV4pr7MiBweLKBwGgt4DhvfZj32Y/WFNANxtYkE9e
55mIPqG5
-----END CERTIFICATE-----

Binary file not shown.

Binary file not shown.

View File

@ -1,46 +1,46 @@
-----BEGIN CERTIFICATE-----
MIID7jCCAtagAwIBAgIULWwn/gLcPMAO/7oGqx5A306mxckwDQYJKoZIhvcNAQEL
MIID7jCCAtagAwIBAgIUKiF/FG2pQjlbId3ox+nQHL/tJ4UwDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0yNDEyMzEwMDAwMDBaMIGdMQswCQYDVQQG
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0zNDEyMzEwMDAwMDBaMIGdMQswCQYDVQQG
EwJQTDEZMBcGA1UECAwQTWF6b3ZpYSBQcm92aW5jZTEPMA0GA1UEBwwGV2Fyc2F3
MRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEUMBIGA1UEAwwL
Q2VydGlmaWNhdGUxJzAlBgkqhkiG9w0BCQEWGG9zc2xzaWduY29kZUBleGFtcGxl
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64qSULdxvTp7A4
2dl/JbLq7GJ4ZcPbtfUyvVTB5WuntN08bpgnxljON0Ig9lFpN2OOlms/SnodlE6Z
O8GY8kYu/aK3zHIHp3EykzRP1glf7ukcCMpcSaS5VUho0QQ9PVvvMHVNtaQ00r2i
34m8DbGj4aRUNI5eA6Xlzz8QnhvCgtRTVbp5ZRjxo1ZNq2eEZxa6UnFshlx6i0/o
kYPrdKTIvUv2zoRFd9H/7+B2Xwse+qppcZe0BiKSa4l6PrL2iHteYE29ggLLSqe+
zavGN7Ev7jP+bZLU/5eq58SBy8uFBDkh1FvZEPAnJ2X/vwNzySi6KTliCPc9Jf5G
wSJr+5MCAwEAAaNiMGAwCQYDVR0TBAIwADAdBgNVHQ4EFgQUVeUILLpF5PWz5rAD
iWzV/2oEP3UwHwYDVR0jBBgwFoAU4/q/jYQJtVH8CIsNnt/ZYq1hcgswEwYDVR0l
BAwwCgYIKwYBBQUHAwMwDQYJKoZIhvcNAQELBQADggEBAHckjLcj9mswr08aF7MV
EZTKKh0IOaHj7oh6vLR5Yg2n+E+9Gog/+ulbKXNe/5A9QU2R1NdwZKEeUeSuF4qW
P3JB79BepgR6/VYKyVWH7St4ixy1GtNEFrHWsID212Jd0Rr3+kc9OJUO0aw3nvg7
Apsr1dztjwlUN2ugLzVoDJ2wMqlu5ZQW8pINIYet127cX5knW/acPCPcqPVD7jmm
C40xgqeKD2a6OafSS5hjO4UeCoeHnXlJ4Sep8wz8VDlu39Hr4dwFm8v9MuvBusCr
/sdwzTRAc6mhBL/4PyJrBRhibbTxSaDKBHeWcKpmNp4DIk1vc8h6yhDUb1fgafgX
7nI=
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMdBCaytt9xsrUx0
2Fekq+IrsR2cC1pL9NANN3TbBv8RKt1IefMh8TjA1uPaOYZvz3o2ml9qKGmJ+uxH
kzLojKbg98bcmxBrkWemLQwmRv1hZIO8D4xiYRd0O0KZizrvwWwlNADzXXWw7iz+
MPPWkXj2nT5MpOTi3S851SwOc/c9SYCazCP8rMGItKHLO7iCjK3sFwBDI9eaTd2N
EjqEHadIymHRizeTOaYv34FokQiRgR/zk4flT6+b6DQHxnlbIivV61OP4bBlFtXX
jC4iGdHLIahhVMlw6ixGqR6910psIp0ST0KM8ly+N+1rPhoNkNSLqkzGUudKo7mV
t+Cp4EMCAwEAAaNiMGAwCQYDVR0TBAIwADAdBgNVHQ4EFgQU6a4Ta3t0UCTG04bC
WMCotMPLyWUwHwYDVR0jBBgwFoAUZBDxqzk33MH9ux3IP0FYd2In7ykwEwYDVR0l
BAwwCgYIKwYBBQUHAwMwDQYJKoZIhvcNAQELBQADggEBAN2Sad4rLRSKWmaRRUCn
syRO45y7zzvCRApHVSoeBUmtHP+n/OZ3rJTixfluqiGFAqbaXgTN8IantyfqoTjV
XgCP1qzSM3staLCkeAiZ0/OLW+hyHopP8aXX2ez/hMojB/J1b457+vkuudnNiLx8
by44nonUnJb3zyxmCSxcBklNP1wlxYjbbq5hFJ/et2/Y5Ct6igYAEMsYZUEUq3e7
g2GWbqNN/i2tnJyGjDPrNRdOuODuclfIDnYSPn83a40XHn+Hgl9SmoXuSdDutAXC
b017GsOa7OV3ZPildcIa3d/yk4S3L56SdoY+Py4NIIDmxcjji1e91qCrrFfGYwmg
TkQ=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----

Binary file not shown.

View File

@ -1,47 +1,47 @@
-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDszCCApugAwIBAgIUdUqeYLe6em9A4BIXcQhE2lS8KTUwDQYJKoZIhvcNAQEL
MIIDszCCApugAwIBAgIUN3RBnJCUJ8HmbeNjJZ/6jsXJLGEwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBnMQswCQYDVQQGEwJQTDEVMBMG
MTgwMTAxMDAwMDAwWhcNMzYwMTAxMDAwMDAwWjBnMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEfMB0GA1UEAwwWSW50ZXJtZWRpYXRlIENBIENSTCBEUDCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBANoHRxZ1qxQKLm8MLYswvTf9FBq05unFxE9j
nea4njWqBkg3cT/jZo2sDHlkN+q3BFEL/K+mej0/LqfW6eXrskHj6OLyXas2/HR4
UYsby8djwazvt4LLiMS5yfo3GlRv5p44F1ruYu7/km7J/6pUxQMB+lTXKA4TzUWe
n/xa2xGm0ZDXvQC1GlPJ1mD/fm0JeS6g8iMdTfvKPKKFMArz+wGWBiqbAKnmuDfp
J3j64nWyRCArH+tGgvOmqkXAUBh9A0T1AfdF1Q5kFKzFq38zKI6lPELo0qEio9SO
W+aOVVDtknTXmqKtawFyhn2e3UEzISYmFv2Wfc/dLnmBzRLNR9cCAwEAAaNmMGQw
EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUYbtAOknHjmiu3l8ONAUY387k
Fi8wHwYDVR0jBBgwFoAUWIpzlJI+vefcJwcNGHwwRms/2ncwDgYDVR0PAQH/BAQD
AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQBJ69rsOHP4qKnu/wRS/D3fV/voLHB624Rg
RpC4RshZMPVL60LaouJo1GMHj3IwyHVHGFkTxGYP0IIgcMUCnkmpSfX1tahYU+kB
4fSCxheLg79g2y3Z1jTQxFOvRjn5t4BIk4Rq4o9E7n1x+8jcaCBSjmna9j6i5lgA
QjazvdXrhhgrkvvMtk2wtk1laiHUHFgb9zxzNhhZFzy+QXwQv+Zj1N0swKfTP2gK
Rxls7e47SnMdvthINZpdvUwT5pBZnMKHqgQK6YbWcopBpuw7zOTJp6Ghqzqzwa4d
CwUtEB7f0e7dWeG7DFJ2cNPcpXaigNtvfdRR3W1RduX9FCODihFF
hvcNAQEBBQADggEPADCCAQoCggEBAME32IBpxW4FhVuZe1PTarEskVHP233QjZtx
poC67/lUK44gtFmsxYsMrDYmmny5pfoM/Byxl5/rorEddLqtDe1kd1SpXUvEYxox
s5rizRd5sZPgkwNoJkSVyNZFwj7gKZHeg6IQHSxNgmTybZ+eZqiNvEveksj3lGpM
Xrbiew7cXUyIP636GPtYxLyIbwDVP0jScqcA/dmSAqofFVUi0SW3OS1hpyXAmmx8
hQHJRKPjPgitZVgjwf5X8/eMTa+ca9dRlRFLk7AcbkF6NcbLm+cRo816nO0EBFV4
Sn2dW9uYqJIfZcpRQ7wbv4fUCghwrk9h3gXrb7AweyK8nyYlmosCAwEAAaNmMGQw
EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUFDxiqeJxiJbmZ4erKH0pBIhq
7SMwHwYDVR0jBBgwFoAUGjxG/vql0oJgItr7HsLaW+koiMgwDgYDVR0PAQH/BAQD
AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQAlI/1XnGc9WzL53rRascZc1EgWAnej9YFS
Dax5+nozYTihC8BRxGfSh1FGRVsmFWhZ0z0XogJJC2bZrQ/36+vwoILItcsWHrQr
rFoZa6s1Uo7ZCd9SfmXjbhMLQgydocCh9YIF66CAkQLwRXc1QIpF7nuZ+rxk0ru1
uGjjBrFRfdSdzlFnyK6wfFzi6LtYDVgVEHC7zzL9E/cyuGo7qQ++SoOg99HjTVY1
PS3ea522bRO2bJpYwZJvvbg020DAfm686VXwAadODdBkI2h6U5SwTxp4SkSmq9SI
mjtERFtnAKD0R2YrX4RzuIckezvwsqLDkQjMnI9XQmv5HWUZimcC
-----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-----
MIID6jCCAtKgAwIBAgIUW4SefwoiLUfTBaHpZyd8knsGVBswDQYJKoZIhvcNAQEL
MIID6jCCAtKgAwIBAgIUcgUgRT1Lx8XLdgp7xcWxVl9YBjYwDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0xOTAxMDEwMDAwMDBaMIGZMQswCQYDVQQG
EwJQTDEZMBcGA1UECAwQTWF6b3ZpYSBQcm92aW5jZTEPMA0GA1UEBwwGV2Fyc2F3
MRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEQMA4GA1UEAwwH
RXhwaXJlZDEnMCUGCSqGSIb3DQEJARYYb3NzbHNpZ25jb2RlQGV4YW1wbGUuY29t
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvripJQt3G9OnsDjZ2X8l
sursYnhlw9u19TK9VMHla6e03TxumCfGWM43QiD2UWk3Y46Waz9Keh2UTpk7wZjy
Ri79orfMcgencTKTNE/WCV/u6RwIylxJpLlVSGjRBD09W+8wdU21pDTSvaLfibwN
saPhpFQ0jl4DpeXPPxCeG8KC1FNVunllGPGjVk2rZ4RnFrpScWyGXHqLT+iRg+t0
pMi9S/bOhEV30f/v4HZfCx76qmlxl7QGIpJriXo+svaIe15gTb2CAstKp77Nq8Y3
sS/uM/5tktT/l6rnxIHLy4UEOSHUW9kQ8CcnZf+/A3PJKLopOWII9z0l/kbBImv7
kwIDAQABo2IwYDAJBgNVHRMEAjAAMB0GA1UdDgQWBBRV5QgsukXk9bPmsAOJbNX/
agQ/dTAfBgNVHSMEGDAWgBTj+r+NhAm1UfwIiw2e39lirWFyCzATBgNVHSUEDDAK
BggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEAp06uHnxO63Ecn+knaXkfrNGg
pr+4WCc0onXYOE37+IwsCFaUqCIr1UsnnKWSzSlSR07FHI+VaV9r3knT6VPMVsUU
L89jHC2vLUvyJJOtuTpuOVGIzzCquYWvYRZrp2wmTceMSNhLcO1VGs28uwQojWEQ
ZsEdFvkYeWFInUQ1mF0dLnfQjh7RcTxMJ0CxZblJ086j3AbyzM6ZF6XAVPAqBH/S
gsBfLVGnZnMOwvKwsxViG1ikRusO6GtcIy6yxmNCUhWbIL+R59EYy++x3xLVUU90
YnScDN+xM9A2wHO1hQpLK6DIiHpbAzAgll5xD0JWh+efRWHEtGN5JTybowG9yA==
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx0EJrK233GytTHTYV6Sr
4iuxHZwLWkv00A03dNsG/xEq3Uh58yHxOMDW49o5hm/PejaaX2ooaYn67EeTMuiM
puD3xtybEGuRZ6YtDCZG/WFkg7wPjGJhF3Q7QpmLOu/BbCU0APNddbDuLP4w89aR
ePadPkyk5OLdLznVLA5z9z1JgJrMI/yswYi0ocs7uIKMrewXAEMj15pN3Y0SOoQd
p0jKYdGLN5M5pi/fgWiRCJGBH/OTh+VPr5voNAfGeVsiK9XrU4/hsGUW1deMLiIZ
0cshqGFUyXDqLEapHr3XSmwinRJPQozyXL437Ws+Gg2Q1IuqTMZS50qjuZW34Kng
QwIDAQABo2IwYDAJBgNVHRMEAjAAMB0GA1UdDgQWBBTprhNre3RQJMbThsJYwKi0
w8vJZTAfBgNVHSMEGDAWgBRkEPGrOTfcwf27Hcg/QVh3YifvKTATBgNVHSUEDDAK
BggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEA0AxgPkboWfIOMYFOP6kQ4nxY
jQ+kAH842ALjm/5z20fYPS0k3LiCNS0FfBPzygeWQLwDGcH2QX6Lfec62CeIe9R9
IAdsX+nNxn9FeIZssfMK3EPgksGUybUNub78mXPrnhCNjYf/GmDY/Cf7jhBtNphK
6zCPOC0WDrupnLW7r4FyrB1j2CEgaHhiSmlQ+19rqbvcNfaCOMfe7IfiwkvVIzE6
tQhnudB/HnW3+pWT83n/KQk0F8lu00fahkak/0bPidTe4zOvepabiWYQXKJ9ZXhm
UW7FHHSM5Vbn2A6zyEht7rcK/gkpHbkckoIi6bDMFMp+K9o3qV7PzZPkaau7fg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----

View File

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

View File

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

Binary file not shown.

View File

@ -1,27 +1,28 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAvripJQt3G9OnsDjZ2X8lsursYnhlw9u19TK9VMHla6e03Txu
mCfGWM43QiD2UWk3Y46Waz9Keh2UTpk7wZjyRi79orfMcgencTKTNE/WCV/u6RwI
ylxJpLlVSGjRBD09W+8wdU21pDTSvaLfibwNsaPhpFQ0jl4DpeXPPxCeG8KC1FNV
unllGPGjVk2rZ4RnFrpScWyGXHqLT+iRg+t0pMi9S/bOhEV30f/v4HZfCx76qmlx
l7QGIpJriXo+svaIe15gTb2CAstKp77Nq8Y3sS/uM/5tktT/l6rnxIHLy4UEOSHU
W9kQ8CcnZf+/A3PJKLopOWII9z0l/kbBImv7kwIDAQABAoIBAQCEsjqNWcLPi53a
kFOSblKuf6FkidxUP2QEa/8rH5UeKBtA6rEQEGyCkUgFLKX00r4E+MpTaD/LYxUy
8o6PDnlSt5MlSbhnhkfMDKI6/WkwMJ0rd6PuF/PtNj3OGY+D4Y/1jSAsHZtJ2q7d
3pqlXEAy3pE6IpRGkcb8AD8H4+n96U4sNnytll6//5uD55PRbxZwB0mmNJOVoZJK
+CbW0wV3rKS0UslFot/b/jNvmCQym3UmWz3elShRTZTA7cdQt2YtKaFO5zFxbbh/
L0+Rija2tVyUPswSbeGxiyfF2RRt++91S6RONfc9B0JKwkNkbQEcM+dPIfIe/nIc
8CgSCUThAoGBAOUMBWLhxE6QW1KeR59d00wtnWzN7x1CQ43LciIRMz3C8BQLpRmX
DmTDASxy9B19tEhdVHzYhq/+1x+vM7TWiPeLg2IhvFZEhpIdN7J1n0iUI3P08dHn
KmvHSu1XGQfngIMT/Ey9xdMpAxsZVJsScuT3sUxnUKxzFpCvTuiCP4ibAoGBANUq
FyAywSsGCrl77BaQh9GDsrL3i67owfpWMs6JjywfEFdpfGZnJTCvlfKtv/Jrp4jB
p5PM5IOil63RqQXa8/pv9pQr2DUGmKegNhDGgflK5+BcbTpkAYIcGHekhoTy2TXU
BnlKaNy5Te80yEFVfFRejK1rQ2ZqHqZP3WtzBBxpAoGBAOGhAOFSg13dKIjvcKCV
/aLKQIzBJG6PKxrQMeNLTE3n7TXh7saRnlU2H77Yko9GmES845CEf9F5WhNVNLtM
puor3cXac7wLjwD6lTZQVhNaEr6UqW5bqNc5IB9DMF4v99Gn617xhqGnge68+jI0
b0gMk/QuxjLKwIzQlQvH2qxHAoGAaFYXx6zQHAzzBuL/JfRMZmK9/xdniY9oEu5K
JAn0yDXUO9ToDP+Dlpb7IDOndjL3Z9rR+WgamcvlzjCHONR5AyX2XYQwaZP2+GVU
0VU4nRrq8EiNNj1o95Rk7XrcVQrBArXrDUc8mH0jBmihdEkxd+JnnSKZdPGQWvtQ
d51ub7ECgYBHbn8uyl4sHLj6y5L2KjsVFpLJp7OFNv3UUN9TrY+rd+CjmTFBSE52
XaV7v8Ul5nDRom5D5R/z8iFK+3Nx7PJq+WesEAPfNPc+BJFkRdJW6ysp/jHnpRV/
rUTaWgQp5/em1GAvBHa8KAoPAS5WAY/lxByruBSTbUSNuC5gz52xzg==
-----END RSA PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHQQmsrbfcbK1M
dNhXpKviK7EdnAtaS/TQDTd02wb/ESrdSHnzIfE4wNbj2jmGb896Nppfaihpifrs
R5My6Iym4PfG3JsQa5Fnpi0MJkb9YWSDvA+MYmEXdDtCmYs678FsJTQA8111sO4s
/jDz1pF49p0+TKTk4t0vOdUsDnP3PUmAmswj/KzBiLShyzu4goyt7BcAQyPXmk3d
jRI6hB2nSMph0Ys3kzmmL9+BaJEIkYEf85OH5U+vm+g0B8Z5WyIr1etTj+GwZRbV
14wuIhnRyyGoYVTJcOosRqkevddKbCKdEk9CjPJcvjftaz4aDZDUi6pMxlLnSqO5
lbfgqeBDAgMBAAECggEABtHIBfvwFgA2Mi6xlNZS96utJSlJDi8ZUuGQ61Pvul0Z
DXfEjLi1q86VzDiUzXAYNsOVpvxYI7yQNPQCKrTg03lRoaG9QOOdl2GNmyPYPCXQ
Ld4K3jAjyIy21oGwzTSVdyES1ZF+ul9y12FfxYirc+tk2FQBNMA697nP/PEFsQl9
cMxBB5CIGH7jSI6UIbp99Kd90ScbnE2mLACM3d0s0sRq783P9yJGpM9a71XE/K2p
CxoRxwqmNRGvI5LrGs1zIF2BSZZgNT71cdfMnAIJBeaoNY7QTKDQlg9xQojE+0if
is16mMhrHQbIFBSxHDRR4uVdiY4iKDB6Lg2pMGcjUQKBgQDzWI2O8bh+YvaEM9QN
uUC1LI6oGzj7+wxkIhjXhCX680EFeJk6AQqNfu5VoBN/nrCXxqjNGKhjqDmtzxjD
y9LYTCJ8rM9eCkrgcdCFkTQNcdNT/zqkHeOIxsoXgsFLhYozWcbiW+8oe9MTrXX/
m9u9kTHkSjKziof7wxGXu3pAmQKBgQDRnYd+urSG0bulBccqT06pJpQMjYIi6CqQ
LYEkLlELxOT+EPeEH1ZdgYkDzzgKoO5L/Jp0Ic6kKEQv+o4l+g1gJp6V5wwX81nv
FJApcg51Yma6WQb6PEJ8HiZ531JQpGZZPmJvRIvEdqw+Dz/dferTApvOlD9s4PfM
xG4R/EoFOwKBgQCEQdW2IhQWxOycj5qp1syfa1chcKI4+YoThiCgSZdm2/yz34bP
6q70lk8sxHK0gugRpYwq5ELo3w5yM8OO7uFqY36+6iFOSCPH9rPRVEjJIdsspOQX
PJNkzD4cJxmtVSf2ns2kSzkhdKMU58rhILF+R0Kpg9YolJsxrySJpgBcyQKBgQCC
KCTYRiqOhHDVuU7AMNqRIclQOhYSgsLbH8ZOpwvgGPRv5i0rNyIzkZl4ahVMVD1j
pYhqkAt11yLv/86AOlJP3+sc/Yh+3rZ7Q/N4KMBdlypej6VLgFtwInCVwFumg06i
H6CToqZ+6YluR53KdMN5HueMUHVJsC9uUJJgTJ3RvQKBgFPi8mgG4zcdoKBhqyq2
x3VQEe0VYnzBsIz42E/NFpuB4ZwC7j0Uez+QFUj76UKMsoE6fX9/lGNdg/zitRBc
M21R9HeWuQHSM6nJ/ScK7C0vqQVsGOr/DKGEydvSjkPsyIbCw8qEdOq8idAULEKj
GlIpzzm+MYzra4yB4VpRw5ES
-----END PRIVATE KEY-----

Binary file not shown.

View File

@ -1,30 +1,30 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,B9C24663685D6009
GMA8W6sGC+xtNYoPzX2j0driKlngRIbmABYMbm8TSac8du7/S8uBcG2i6z/d0Plu
pHr06uIcZDjCN0iWkhMGS7ai40ddBjxjDS/f9ppUZdOtTX4MzGfqb/d9LGVi1P8W
zYSuz7BI0B2ttcbpmMIhxdGMtRz8A/MDPm8eBnEmIYjRiW/ES2HfHlrm7CFlrd72
vgiAmFPtx9P5AE+KMFiSJDkSVMKX52yvLfBQAeBU2aQI7z5BTfwIpGgVKBT5qhq4
EwL24FrEJ1+20Q/Resd/nfqv6lzNPl6SQLhCgY25Yz0Ke9u8Xnhn1aoz1BCDtw8u
fnzmaqexf6w70rC1qX+CyrHLxO19lRUn5wChyPYaU2oAt3a0iKktQWdqHUIAGi+d
Q3DpgsXlQXuXHDeBh5KKePz6g1f7pjacpjH8t8Y3VqurQop8Ku5KiVln+WyVklbS
9ipr4Btf8NnWWD+kAvdo01ObRRGYxZwj/mlr9ePQ2d2vd9wNLe8zS0FZSzBE7cZH
OPMuZnjU9Ruub0GJpHzsNBhMNIl6M6c2DSphrUTZBG6Sogx/aVSxe3Z5sojULfNT
aifhUP/qR94nFokwRs77zXwWJlIF02g6caL8P/fPAcxIaItl+Q3DFo0wEZOzDI2X
7ijPoEj/TReVajulxCcISJs5F6gaPKhNW8FKxvFH+3LnMLW/BeHNSGgnIFftkI3Z
GqwcLN+X76qhPzS1UFF12fW9wYXjhMnR6bvVaadP6+XadZonyE+eGdRjZH0M2IIF
Jv6si9Zxw+sesmmFXzjU0jzv825rD0NtPpYKWaCdtX1x5fkk+A4T28Yu1uLWfJcs
4LhEkfhgILjLY02idjX4OKmwKm4w+QqBeajBCZiGTl6Fk2mvC0wCy53AEH3UTu8I
KRkEAcl1CxsYAHZb9B00ymk3iyGTQ/1luLZfPkGS6CMJPXjSjR0i8NmOaYa+Xhe7
bsCPYWeGT1ttJh+A5Dh39K00lSrIuQS9m3lKzdlHhZ8YL8DdeUAMBM6JKI3p8V9s
xeb/w9Vf7iZRLsL6yDqj4zm5HFifRpFDpD/E2rC6zpUvdFiy2p6J7Xpo2cu3wMIV
QL1te4aHVQhWsijV7LoaS3452NOnknxiNxXFWk2POwPHL1i6rmS7MlQwqDlLBilj
O2R4YZGjmRg69zr9xJJGQQnroFEagKdhedSJ2y+lqwxl1Kb+Lp0+SOVesxfjfoeZ
y0ctY7IJZksM0htETT6fhfJKSbMfM2uRL3FJkv1QyexnIlwmZxZgUyYAJemTZJBY
BbAhhmTRswhp5FWdfFbYez7cV9AIhtNCoGcNQuQ+wL9OmIQbmZjFUqLIcHVyX1xA
Zj5Jh6aybmnJTdXyIwUP3RdkHrD5JW8+d/0xMm1G89PtDJ6Q2+D3drtTB7A3ruUD
uyDhYtpyY9m940miAsvByK2jIUlA0hLb+9+1oiWcWarl7IwxpjP8CUG6nAF7BU6v
J/Hbikx0XMfycYp1EsQYUP4ku+S/PoJsMNU4bt248E+dDALxoyQN1Z41sYILBz4Y
ga6z4zCA5+66ug8z2yMbC4bCo0FZxuJLcw+Ok05+PT0fW9Z3egpybXVwwY4wc6vs
-----END RSA PRIVATE KEY-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIY7PpABd5xsYCAggA
MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECC8FH8kZE5H/BIIEyK9LnEmc3VYK
kqwBBX15exPIRrsmeGkoSSrnHUeLzV0E2CN9bEL1XwJtX6d4YGYHnH7MopV9LPgl
Fdu2CvWXt5XLOMb3FJ38zZGtNnbYWZLbVlgQANZaTRCZaoWHS57KulgbtbJnn3PQ
DdYHaCiRh95pgPrdklEs0PhvBe98kR4xGJPoiGn+gJ75Ik4kwW/vJTcQeKbcU4oQ
MGIVXV66NU+Pc1d3CTYm9hwIys70+J9QtT1aSoENeYr1e+sHgzN7ykDalfAir/dZ
/E91Zg4RFV4clvvVmoAyXmZFpMxj5pLYGvdjBxTURh+8mdulfJMpKHjJldx7N9+I
cusGwKVXQcIXI76lxvKo08oENq0C6112+++s6bYtwzuk/Auk+dQ2mn2/gLgs6fsy
pi1ZKUoO8pdm8N4QzqPsFc2/ny5oSy6A6EKDC/tKoP59r6qJtoYselfypFsWemIo
F/W0HmZzC5OJMEqUxbKIuH7Xhx0ufs4TytzYMEnUVH0ChLan67VvFIcq4sLoMaW0
d2jyDdIe4WcmVckJtjudbIhcRsXtoSVB8PYjdHOmI9YZVksPreeKk7stf06V3PBU
/hsBpzlWu8xO6+cMGrlvoqOov3WAmD1/LW/ITggjLb28r7LnUrYTbj95xZ8Zd8s9
hx60MZpTJKni/Kfd5yVZw7xZWLHxNWdBbZxlCkvvFN5Ik0FjULLblfIfYa38zwp1
P6Dbw0wBSNhpsdsGcnkB+YWlzyIJzC99EZqgC3cGmb+9UGuj2bmvzx0hlIY4APCf
lfiFNXUHxxRZCV/Cp3TXqh3h7t99KvVoIzEIV8iUDMLG7dsnf2Y1z7AQ3cfL8tmC
qTlKH8QdMn87ntjcU1fynE3X/bL4+Fy8ZWeCWHHPLU2TP6Z7xBkXVB77gm0rK2cU
lJVZKB3kVemSvu9OennBAiE7yjusqCLyTJo9GlI3H7xM+jHf0CZM149n2yV7w98Z
Nag2b4iYnbVa1CRcL+4Y5zfA6AwCXvkqKcqyUqK4ZEvd1VnN9L+pTWrxaAxukC5f
KyKXKd+HdiS2b8fFVYKmpq+lK02zxuIJpLh7JlcztNinm67irwg+7VZczpX46Za1
waPuAnJ6zA6pVdRKxpXx5AnAh9vlCtlyakREx6NajG7f2nCe6IrznyVQ45jlkmwp
od0kAjsd/xp0NyvWI5A9ICU+pJ5xqhUGkXPvIxj1IqTFa7k4lYKiKgqeKoyLnzYA
+R1iQikwewxEahamhjiBH2xPYmZ77EjIF3EtLbpI02fxHR8LjyIBJ/HNnarKqJp0
HYhLJQ8z7uyAESfXY997UnTtgLQHEX5/6DKYqlNWdzRiIEGfleujHmaAb9kf9Xrr
r2EVc0E4q2/wvgMHn8GRSv6K7pQC//vNmBuNGCAMBl8t6y1QxDrX+UBn97HGk96Z
LqRoVM2mz1cS/tiP4+MSB0zqzGbHsk9xoEY0QeRPvjJfGc1skRWwdo8LA8Hf1pi1
/exyJzHNdxVdxM4CKMnXbTNCxKlhhZhUaWzELNjI5bQ5oQfechEypsFYAQETU5NS
182MgLMhkxqqcxLHcHIGE1ApZKXhY5siO0k4TTb2Kqxgn2fBUyLQLMVaVrHhZwxg
XwiQ2Rt3JBHrzPy9wXL8hw==
-----END ENCRYPTED PRIVATE KEY-----

Binary file not shown.

View File

@ -1,45 +1,45 @@
-----BEGIN CERTIFICATE-----
MIIDvTCCAqWgAwIBAgIUSXAaPeUatfheDTFo77LnMBHgyeMwDQYJKoZIhvcNAQEL
MIIDvTCCAqWgAwIBAgIUazbrVgbYb+IN803UmJJa0DPHQsAwDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0yNDEyMzEwMDAwMDBaMG0xCzAJBgNVBAYT
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0zNDEyMzEwMDAwMDBaMG0xCzAJBgNVBAYT
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEQMA4GA1UE
AwwHUmV2b2tlZDEnMCUGCSqGSIb3DQEJARYYb3NzbHNpZ25jb2RlQGV4YW1wbGUu
Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvripJQt3G9OnsDjZ
2X8lsursYnhlw9u19TK9VMHla6e03TxumCfGWM43QiD2UWk3Y46Waz9Keh2UTpk7
wZjyRi79orfMcgencTKTNE/WCV/u6RwIylxJpLlVSGjRBD09W+8wdU21pDTSvaLf
ibwNsaPhpFQ0jl4DpeXPPxCeG8KC1FNVunllGPGjVk2rZ4RnFrpScWyGXHqLT+iR
g+t0pMi9S/bOhEV30f/v4HZfCx76qmlxl7QGIpJriXo+svaIe15gTb2CAstKp77N
q8Y3sS/uM/5tktT/l6rnxIHLy4UEOSHUW9kQ8CcnZf+/A3PJKLopOWII9z0l/kbB
Imv7kwIDAQABo2IwYDAJBgNVHRMEAjAAMB0GA1UdDgQWBBRV5QgsukXk9bPmsAOJ
bNX/agQ/dTAfBgNVHSMEGDAWgBTj+r+NhAm1UfwIiw2e39lirWFyCzATBgNVHSUE
DDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEAK/bCZPrxN+5HGQjZLIQg
jKfjTRL5xwBGs8+VW4i+xnaA14pyZjDlYzASmCE/ZiryVSMJ7fuQ0TVXGtz3N7PM
v9pRgtcohs62NJZ5dIrq4f/Op1bii29pAA8+2EHPJUyFBt23vyvlI/dBpkgQG6mi
OUEsXQ+Q2LUD4OOJffkc/gowXcB4WFjrtFAUuu9HeZUNzV5Mm5FQTGm9nCnWsDIb
b7Yx08hMy+6jtvkNPCDcFnos2bsipmVN4fCXkm5LPZNyMFoWReDbIKWASXaao2hN
gzWhwWsPlAGAlBPMVWEo3k2Cz/entbAijoyqS2koN4mZABy7m5+vfzFw/yvh1/lu
8w==
Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx0EJrK233GytTHTY
V6Sr4iuxHZwLWkv00A03dNsG/xEq3Uh58yHxOMDW49o5hm/PejaaX2ooaYn67EeT
MuiMpuD3xtybEGuRZ6YtDCZG/WFkg7wPjGJhF3Q7QpmLOu/BbCU0APNddbDuLP4w
89aRePadPkyk5OLdLznVLA5z9z1JgJrMI/yswYi0ocs7uIKMrewXAEMj15pN3Y0S
OoQdp0jKYdGLN5M5pi/fgWiRCJGBH/OTh+VPr5voNAfGeVsiK9XrU4/hsGUW1deM
LiIZ0cshqGFUyXDqLEapHr3XSmwinRJPQozyXL437Ws+Gg2Q1IuqTMZS50qjuZW3
4KngQwIDAQABo2IwYDAJBgNVHRMEAjAAMB0GA1UdDgQWBBTprhNre3RQJMbThsJY
wKi0w8vJZTAfBgNVHSMEGDAWgBRkEPGrOTfcwf27Hcg/QVh3YifvKTATBgNVHSUE
DDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEAFJjwxpYA2jzrmF1mdKx/
up8gl6iISsHDc7oLAv63oUYXpFwzpNfvi1TGqYVhntAH2t/1XdA1HKdBp2LDsEnt
Av66c6HxyNPka26ZGD70+w5q8uHrIOO6MZw0eaLwu9bJI4cLbRXlKwxkGSzXHGYs
1hGR2YwAiMrqtVMPetlpd62y6qUZc0lEOhjJ6DsIfqSgO8AsdyI7Ao+cDqEZ1I/Q
Oi1Agn8kz8TtfWKxkX06EoL4DrZCDb1/w0CGQJATq77pKst+zw+B+2EKqlpuG3s/
FE7RkCjG7bEFIDEK2909BXQNyQJzp7ih9X8QeEx5fnPr9lDfe/75YjRqoHkfmcTC
Hw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----

View File

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

View File

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

View File

@ -1 +1 @@
55c4d523e595564af0ab635fd1e3aaba
bb7fd13ddf056e0a3e621d3537b25478

View File

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

View File

@ -42,11 +42,11 @@ make_certs() {
echo -n "$password" > tmp/password.txt
################################################################################
# Root CA certificate
# Root CA certificates
################################################################################
printf "\nGenerate root CA certificate\n" >> "makecerts.log"
"$OPENSSL" genrsa -out CA/CA.key \
printf "\nGenerate trusted root CA certificate\n" >> "makecerts.log"
"$OPENSSL" genrsa -out CA/CAroot.key \
2>> "makecerts.log" 1>&2
test_result $?
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
@ -54,11 +54,48 @@ make_certs() {
OPENSSL="$0"
export LD_LIBRARY_PATH="$1"
CONF="${script_path}/openssl_root.cnf"
"$OPENSSL" req -config "$CONF" -new -x509 -days 3600 -key CA/CA.key -out tmp/CACert.pem \
"$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" \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
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
################################################################################
@ -146,19 +183,6 @@ make_certs() {
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $?
printf "\nGenerate CSP Cross-Certificate\n" >> "makecerts.log"
"$OPENSSL" genrsa -out CA/cross.key \
2>> "makecerts.log" 1>&2
TZ=GMT faketime -f '@2018-01-01 00:00:00' /bin/bash -c '
script_path=$(pwd)
OPENSSL="$0"
export LD_LIBRARY_PATH="$1"
CONF="${script_path}/openssl_intermediate.cnf"
"$OPENSSL" req -config "$CONF" -new -x509 -days 900 -key CA/cross.key -out tmp/crosscert.pem \
-subj "/C=PL/O=osslsigncode/OU=CSP/CN=crosscert/emailAddress=osslsigncode@example.com" \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $?
printf "\nGenerate code signing certificate\n" >> "makecerts.log"
"$OPENSSL" req -config "$CONF" -new -key CA/private.key -passin pass:"$password" -out CA/cert.csr \
-subj "/C=PL/ST=Mazovia Province/L=Warsaw/O=osslsigncode/OU=CSP/CN=Certificate/emailAddress=osslsigncode@example.com" \
@ -319,7 +343,7 @@ make_certs() {
OPENSSL="$0"
export LD_LIBRARY_PATH="$1"
CONF="${script_path}/openssl_tsa_root.cnf"
"$OPENSSL" req -config "$CONF" -new -x509 -days 3600 -key CA/TSACA.key -out tmp/TSACA.pem \
"$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"
test_result $?
@ -377,14 +401,14 @@ make_certs() {
# 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/CACertCRL.pem -a -s tmp/CACertCRL.der \
-a -s tmp/TSACertCRL.pem -a -s tmp/TSACertCRL.der \
-a -s tmp/key.pem -a -s tmp/keyp.pem -a -s tmp/key.der -a -s tmp/key.pvk \
-a -s tmp/cert.pem -a -s tmp/cert.der -a -s tmp/cert.spc \
-a -s tmp/cert.p12 -a -s tmp/legacy.p12 -a -s tmp/cert_crldp.pem\
-a -s tmp/crosscert.pem -a -s tmp/expired.pem \
-a -s tmp/expired.pem \
-a -s tmp/revoked.pem -a -s tmp/revoked_crldp.pem \
-a -s tmp/TSA_revoked.pem \
-a -s tmp/TSA.pem -a -s tmp/TSA.key -a -s tmp/tsa-chain.pem

View File

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

View File

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

View File

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

View File

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

View File

@ -43,6 +43,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
self.send_response(200)
self.send_header("Content-type", "application/crl")
self.end_headers()
resp_data = b''
# Read the file and send the contents
if url.path == "/intermediateCA":
with open(CACRL, 'rb') as file:
@ -52,7 +53,8 @@ class RequestHandler(SimpleHTTPRequestHandler):
resp_data = file.read()
self.wfile.write(resp_data)
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
""""Serves the POST request type"""
@ -76,12 +78,12 @@ class RequestHandler(SimpleHTTPRequestHandler):
openssl.check_returncode()
self.send_header("Content-type", "application/timestamp-reply")
self.end_headers()
resp_data = None
resp_data = b''
with open(RESPONS, mode="rb") as file:
resp_data = file.read()
self.wfile.write(resp_data)
except Exception as err: # pylint: disable=broad-except
print(f"HTTP POST request error: {err}")
print("HTTP POST request error: {}".format(err))
class HttpServerThread():
@ -93,12 +95,12 @@ class HttpServerThread():
self.server_thread = None
def start_server(self) -> (int):
"""Starting HTTP server on localhost and a random available port for binding"""
self.server = ThreadingHTTPServer(('localhost', 19254), RequestHandler)
"""Starting HTTP server on 127.0.0.1 and a random available port for binding"""
self.server = ThreadingHTTPServer(('127.0.0.1', 19254), RequestHandler)
self.server_thread = threading.Thread(target=self.server.serve_forever)
self.server_thread.start()
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
@ -113,7 +115,7 @@ def main() -> None:
with open(PORT_LOG, mode="w") as file:
file.write("{}".format(port))
except OSError as err:
print(f"OSError: {err}")
print("OSError: {}".format(err))
ret = err.errno
finally:
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",
"platform": "!(windows & static) & !osx"
}
]
],
"builtin-baseline": "9edb1b8e590cc086563301d735cae4b6e732d2d2"
}