19 Commits

Author SHA1 Message Date
Michał Trojnara 9ebd79ad18 Release 2.7
Signed-off-by: Michał Trojnara <Michal.Trojnara@stunnel.org>
2023-09-19 21:51:05 +02:00
Michał Trojnara 1700455533 APPX support (#303)
Co-authored-by: Maciej Panek <Maciej.panek@punxworks.com>
Co-authored-by: olszomal <Malgorzata.Olszowka@stunnel.org>
2023-09-19 21:23:32 +02:00
Michał Trojnara a6f767f5a3 Mark the result as not tainted 2023-09-08 14:09:53 +02:00
olszomal 4c5b329bc4 fixed mixed declarations and code 2023-09-08 11:51:20 +02:00
olszomal 5626482e82 fixed a function declaration with a void parameter 2023-09-08 11:51:20 +02:00
olszomal 2d21a2121c squash gcc debugger warnings
remove nsections>UINT16_MAX check
2023-09-08 11:51:20 +02:00
Michał Trojnara 5d2bf2c80f Fix insufficient MSI_ENTRY comparison 2023-09-04 16:10:25 +02:00
Michael Brown 5b8376ce32 Fix construction of signed CAB header
Commit 0f51a06 ("Separate common and format-dependent functions")
performed a substantial amount of refactoring.  Within the CFFOLDER
header construction loop in cab_add_header(), the line

   tmp = GET_UINT32_LE(indata + i);

seems to have been accidentally deleted, instead of being refactored
to become

   tmp = GET_UINT32_LE(ctx->options->indata + i);

with the result that adding a signature to a .cab file will currently
produce an invalid .cab file.

Fix by adding back in the missing line of code.

Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
2023-08-31 12:27:01 +02:00
Michał Trojnara 1fc2c937f2 Secrets are not available in PRs 2023-08-25 09:49:10 +02:00
olszomal 2ed54490a6 Use TS_TST_INFO struct 2023-07-31 17:46:01 +02:00
olszomal a096aa8a33 Set signing digest to generate RFC3161 response 2023-07-31 17:46:01 +02:00
olszomal aa08566a63 Use TS_REQ struct 2023-07-31 17:46:01 +02:00
Małgorzata Olszówka (she/her) c04b229ce2 Built-in TSA response generation (#281) 2023-07-28 16:03:04 +02:00
Michał Trojnara adcfd9a33f Apply suggestions from code review
Added more detailed error messages.
Fixed formatting and indentation.

Co-authored-by: Małgorzata Olszówka <Malgorzata.Olszowka@stunnel.org>
2023-07-21 11:44:55 +02:00
Maxim Bagryantsev f2f3a8891c Fixed validation of supported command 2023-07-21 11:44:55 +02:00
olszomal 29eedf9059 Fixed DIFAT sectors writing 2023-06-30 11:30:02 +02:00
fanquake d6f94d71f7 doc: correct minimum CMake version in README.md
It's 3.17, not 3.6.
2023-06-01 19:43:42 +02:00
Michał Trojnara a509a66c65 Initial 2.7-dev commit 2023-05-30 17:23:46 +02:00
Michał Trojnara 7bf4c92d83 Fixed CI version 2023-05-29 23:25:42 +02:00
16 changed files with 3278 additions and 246 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ on:
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
version: osslsigncode-2.6-dev
version: osslsigncode-2.7
jobs:
build:
+1 -1
View File
@@ -2,7 +2,7 @@ name: Coverity Scan
on:
push:
pull_request:
workflow_dispatch:
jobs:
coverity:
+9 -2
View File
@@ -10,7 +10,7 @@ set(BUILTIN_SOCKET ON CACHE BOOL "") # for static Python
# configure basic project information
project(osslsigncode
VERSION 2.6
VERSION 2.7
DESCRIPTION "OpenSSL based Authenticode signing for PE, CAB, CAT and MSI files"
HOMEPAGE_URL "https://github.com/mtrojnar/osslsigncode"
LANGUAGES C)
@@ -30,6 +30,7 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
# load CMake library modules
include(FindOpenSSL)
include(FindCURL)
include(FindZLIB)
# load CMake project modules
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")
@@ -47,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)
target_sources(osslsigncode PRIVATE osslsigncode.c helpers.c msi.c pe.c cab.c cat.c appx.c)
if(NOT UNIX)
target_sources(osslsigncode PRIVATE applink.c)
endif(NOT UNIX)
@@ -72,6 +73,12 @@ else(CURL_FOUND)
message(STATUS "cURL support disabled (library not found)")
endif(CURL_FOUND)
if(NOT ZLIB_FOUND)
message(FATAL_ERROR "Zlib library not found")
endif(NOT ZLIB_FOUND)
target_include_directories(osslsigncode PRIVATE ${ZLIB_INCLUDE_DIR})
target_link_libraries(osslsigncode PRIVATE ${ZLIB_LIBRARIES})
# add paths to linker search and installed rpath
set_target_properties(osslsigncode PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE)
+9
View File
@@ -1,5 +1,14 @@
# osslsigncode change log
### 2.7 (2023.09.19)
- fixed signing CAB files (by Michael Brown)
- fixed handling of unsupported commands (by Maxim Bagryantsev)
- fixed writing DIFAT sectors
- added APPX support (by Maciej Panek and Małgorzata Olszówka)
- added a built-in TSA response generation (-TSA-certs, -TSA-key
and -TSA-time options)
### 2.6 (2023.05.29)
- modular architecture implemented to simplify adding file formats
+1 -1
View File
@@ -46,7 +46,7 @@ We highly recommend downloading a [release tarball](https://github.com/mtrojnar/
brew install cmake pkg-config openssl@1.1
export PKG_CONFIG_PATH="/usr/local/opt/openssl@1.1/lib/pkgconfig"
```
**NOTE:** osslsigncode requires CMake 3.6 or newer.
**NOTE:** osslsigncode requires CMake 3.17 or newer.
You may need to use `cmake3` instead of `cmake` to complete the following steps on your system.
* Navigate to the build directory and run CMake to configure the osslsigncode project
+2684
View File
File diff suppressed because it is too large Load Diff
+12
View File
@@ -43,6 +43,7 @@ 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 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);
@@ -57,6 +58,7 @@ static void cab_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
FILE_FORMAT file_format_cab = {
.ctx_new = cab_ctx_new,
.data_blob_get = cab_obsolete_link_get,
.hash_length_get = cab_hash_length_get,
.check_file = cab_check_file,
.digest_calc = cab_digest_calc,
.verify_digests = cab_verify_digests,
@@ -149,6 +151,15 @@ static ASN1_OBJECT *cab_obsolete_link_get(u_char **p, int *plen, FILE_FORMAT_CTX
return dtype; /* 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 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
@@ -900,6 +911,7 @@ static int cab_add_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
*/
nfolders = GET_UINT16_LE(ctx->options->indata + 26);
while (nfolders) {
tmp = GET_UINT32_LE(ctx->options->indata + i);
tmp += 24;
PUT_UINT32_LE(tmp, buf);
BIO_write(hash, buf, 4);
+1 -1
View File
@@ -99,7 +99,7 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
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\n");
printf("Warning: CAT files do not support nesting (multiple signature)\n");
if (options->jp >= 0)
printf("Warning: -jp option is only valid for CAB files\n");
if (options->pagehash == 1)
+46 -44
View File
@@ -123,8 +123,9 @@ string(SUBSTRING ${sha256sum} 0 64 leafhash)
enable_testing()
set(extensions_4 "exe" "ex_" "msi" "cat")
set(extensions_3 "exe" "ex_" "msi")
set(extensions_all "exe" "ex_" "msi" "256appx" "512appx" "cat")
set(extensions_nocat "exe" "ex_" "msi" "256appx" "512appx")
set(extensions_nocatappx "exe" "ex_" "msi")
# Test 1
# Print osslsigncode version
@@ -135,7 +136,7 @@ add_test(NAME version
# Tests 2-5
# Sign with PKCS#12 container with legacy RC2-40-CBC private key and certificate encryption algorithm
foreach(ext ${extensions_4})
foreach(ext ${extensions_all})
add_test(
NAME legacy_${ext}
COMMAND osslsigncode "sign"
@@ -151,7 +152,7 @@ foreach(ext ${extensions_4})
"-n" "osslsigncode"
"-in" "${FILES}/unsigned.${ext}"
"-out" "${FILES}/legacy.${ext}")
endforeach(ext ${extensions_4})
endforeach(ext ${extensions_all})
# Tests 6-9
# Sign with PKCS#12 container with legacy RC2-40-CBC private key and certificate encryption algorithm
@@ -159,7 +160,7 @@ endforeach(ext ${extensions_4})
# Option "-nolegacy" requires OpenSSL 3.0.0 or later
# This tests are expected to fail
if(OPENSSL_VERSION VERSION_GREATER_EQUAL 3.0.0)
foreach(ext ${extensions_4})
foreach(ext ${extensions_all})
add_test(
NAME nolegacy_${ext}
COMMAND osslsigncode "sign"
@@ -180,12 +181,12 @@ if(OPENSSL_VERSION VERSION_GREATER_EQUAL 3.0.0)
nolegacy_${ext}
PROPERTIES
WILL_FAIL TRUE)
endforeach(ext ${extensions_4})
endforeach(ext ${extensions_all})
endif(OPENSSL_VERSION VERSION_GREATER_EQUAL 3.0.0)
# Tests 10-13
# Sign with PKCS#12 container with AES-256-CBC private key and certificate encryption algorithm
foreach(ext ${extensions_4})
foreach(ext ${extensions_all})
add_test(
NAME signed_${ext}
COMMAND osslsigncode "sign"
@@ -201,11 +202,11 @@ foreach(ext ${extensions_4})
"-n" "osslsigncode"
"-in" "${FILES}/unsigned.${ext}"
"-out" "${FILES}/signed.${ext}")
endforeach(ext ${extensions_4})
endforeach(ext ${extensions_all})
# Tests 14-17
# Sign with revoked certificate
foreach(ext ${extensions_4})
foreach(ext ${extensions_all})
add_test(
NAME revoked_${ext}
COMMAND osslsigncode "sign"
@@ -222,12 +223,12 @@ foreach(ext ${extensions_4})
"-n" "osslsigncode"
"-in" "${FILES}/unsigned.${ext}"
"-out" "${FILES}/revoked.${ext}")
endforeach(ext ${extensions_4})
endforeach(ext ${extensions_all})
# Tests 18-20
# Remove signature
# Unsupported command for CAT files
foreach(ext ${extensions_3})
foreach(ext ${extensions_nocat})
add_test(
NAME removed_${ext}
COMMAND osslsigncode "remove-signature"
@@ -238,11 +239,11 @@ foreach(ext ${extensions_3})
PROPERTIES
DEPENDS "signed_${ext}"
REQUIRED_FILES "${FILES}/signed.${ext}")
endforeach(ext ${extensions_3})
endforeach(ext ${extensions_nocat})
# Tests 21-24
# Extract PKCS#7 signature in PEM format
foreach(ext ${extensions_4})
foreach(ext ${extensions_all})
add_test(
NAME extract_pem_${ext}
COMMAND osslsigncode "extract-signature"
@@ -254,11 +255,11 @@ foreach(ext ${extensions_4})
PROPERTIES
DEPENDS "signed_${ext}"
REQUIRED_FILES "${FILES}/signed.${ext}")
endforeach(ext ${extensions_4})
endforeach(ext ${extensions_all})
# Tests 25-28
# Extract PKCS#7 signature in default DER format
foreach(ext ${extensions_4})
foreach(ext ${extensions_all})
add_test(
NAME extract_der_${ext}
COMMAND osslsigncode "extract-signature"
@@ -269,13 +270,13 @@ foreach(ext ${extensions_4})
PROPERTIES
DEPENDS "signed_${ext}"
REQUIRED_FILES "${FILES}/signed.${ext}")
endforeach(ext ${extensions_4})
endforeach(ext ${extensions_all})
# Tests 29-34
# Attach signature in PEM or DER format
# Unsupported command for CAT files
set(formats "pem" "der")
foreach(ext ${extensions_3})
foreach(ext ${extensions_nocat})
foreach(format ${formats})
add_test(
NAME attached_${format}_${ext}
@@ -299,11 +300,11 @@ foreach(ext ${extensions_3})
REQUIRED_FILES "${FILES}/signed.${ext}"
REQUIRED_FILES "${FILES}/${ext}.${format}")
endforeach(format ${formats})
endforeach(ext ${extensions_3})
endforeach(ext ${extensions_nocat})
# Tests 35-38
# Add an unauthenticated blob to a previously-signed file
foreach(ext ${extensions_4})
foreach(ext ${extensions_all})
add_test(
NAME added_${ext}
COMMAND osslsigncode "add"
@@ -316,11 +317,11 @@ foreach(ext ${extensions_4})
PROPERTIES
DEPENDS "signed_${ext}"
REQUIRED_FILES "${FILES}/signed.${ext}")
endforeach(ext ${extensions_4})
endforeach(ext ${extensions_all})
# Tests 39-42
# Add the new nested signature instead of replacing the first one
foreach(ext ${extensions_4})
foreach(ext ${extensions_all})
add_test(
NAME nested_${ext}
COMMAND osslsigncode "sign"
@@ -344,14 +345,15 @@ foreach(ext ${extensions_4})
PROPERTIES
DEPENDS "signed_${ext}"
REQUIRED_FILES "${FILES}/signed.${ext}")
endforeach(ext ${extensions_4})
endforeach(ext ${extensions_all})
### Verify signature ###
# Tests 43-45
# Verify PE/MSI/CAB files signed in the catalog file
foreach(ext ${extensions_3})
# APPX does not support detached PKCS#7 signature
foreach(ext ${extensions_nocatappx})
add_test(
NAME verify_catalog_${ext}
COMMAND osslsigncode "verify"
@@ -367,13 +369,13 @@ foreach(ext ${extensions_3})
DEPENDS "signed_${ext}"
REQUIRED_FILES "${FILES}/signed.cat"
REQUIRED_FILES "${FILES}/unsigned.${ext}")
endforeach(ext ${extensions_3})
endforeach(ext ${extensions_nocatappx})
# Tests 46-69
# Verify signature
set(files "legacy" "signed" "nested" "added" "removed" "revoked" "attached_pem" "attached_der")
foreach(file ${files})
foreach(ext ${extensions_3})
foreach(ext ${extensions_nocat})
add_test(
NAME verify_${file}_${ext}
COMMAND osslsigncode "verify"
@@ -386,18 +388,18 @@ foreach(file ${files})
PROPERTIES
DEPENDS "${file}_${ext}"
REQUIRED_FILES "${FILES}/${file}.${ext}")
endforeach(ext ${extensions_3})
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_3})
foreach(ext ${extensions_nocat})
set_tests_properties(
verify_${file}_${ext}
PROPERTIES
WILL_FAIL TRUE)
endforeach(ext ${extensions_3})
endforeach(ext ${extensions_nocat})
endforeach(file ${files})
if(Python3_FOUND OR server_error)
@@ -409,7 +411,7 @@ if(Python3_FOUND OR server_error)
# Use "cert" "expired" "revoked" without X509v3 CRL Distribution Points extension
# and "cert_crldp" "revoked_crldp" contain X509v3 CRL Distribution Points extension
set(pem_certs "cert" "expired" "revoked" "cert_crldp" "revoked_crldp")
foreach(ext ${extensions_4})
foreach(ext ${extensions_all})
foreach(cert ${pem_certs})
add_test(
NAME sign_ts_${cert}_${ext}
@@ -432,14 +434,14 @@ if(Python3_FOUND OR server_error)
PROPERTIES
REQUIRED_FILES "${LOGS}/port.log")
endforeach(cert ${pem_certs})
endforeach(ext ${extensions_4})
endforeach(ext ${extensions_all})
### Verify Time-Stamp Authority ###
# Tests 90-92
# Signature verification time: Sep 1 00:00:00 2019 GMT
foreach(ext ${extensions_3})
foreach(ext ${extensions_nocat})
add_test(
NAME verify_ts_cert_${ext}
COMMAND osslsigncode "verify"
@@ -453,11 +455,11 @@ if(Python3_FOUND OR server_error)
DEPENDS "sign_ts_cert_${ext}"
REQUIRED_FILES "${FILES}/ts_cert.${ext}"
REQUIRED_FILES "${LOGS}/port.log")
endforeach(ext ${extensions_3})
endforeach(ext ${extensions_nocat})
# Tests 93-95
# Signature verification time: Jan 1 00:00:00 2035 GMT
foreach(ext ${extensions_3})
foreach(ext ${extensions_nocat})
add_test(
NAME verify_ts_future_${ext}
COMMAND osslsigncode "verify"
@@ -471,12 +473,12 @@ if(Python3_FOUND OR server_error)
DEPENDS "sign_ts_cert_${ext}"
REQUIRED_FILES "${FILES}/ts_cert.${ext}"
REQUIRED_FILES "${LOGS}/port.log")
endforeach(ext ${extensions_3})
endforeach(ext ${extensions_nocat})
# Tests 96-98
# Verify with ignored timestamp
# This tests are expected to fail
foreach(ext ${extensions_3})
foreach(ext ${extensions_nocat})
add_test(
NAME verify_ts_ignore_${ext}
COMMAND osslsigncode "verify"
@@ -492,7 +494,7 @@ if(Python3_FOUND OR server_error)
REQUIRED_FILES "${FILES}/ts_cert.${ext}"
REQUIRED_FILES "${LOGS}/port.log"
WILL_FAIL TRUE)
endforeach(ext ${extensions_3})
endforeach(ext ${extensions_nocat})
### Verify CRL Distribution Points ###
@@ -501,7 +503,7 @@ if(Python3_FOUND OR server_error)
# 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_3})
foreach(ext ${extensions_nocat})
add_test(
NAME verify_ts_cert_crldp_${ext}
COMMAND osslsigncode "verify"
@@ -515,13 +517,13 @@ if(Python3_FOUND OR server_error)
DEPENDS "sign_ts_cert_crldp_${ext}"
REQUIRED_FILES "${FILES}/ts_cert_crldp.${ext}"
REQUIRED_FILES "${LOGS}/port.log")
endforeach(ext ${extensions_3})
endforeach(ext ${extensions_nocat})
# Tests 102-107
# 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_3})
foreach(ext ${extensions_nocat})
foreach(cert ${failed_certs})
add_test(
NAME verify_ts_${cert}_${ext}
@@ -539,13 +541,13 @@ if(Python3_FOUND OR server_error)
REQUIRED_FILES "${LOGS}/port.log"
WILL_FAIL TRUE)
endforeach(cert ${failed_certs})
endforeach(ext ${extensions_3})
endforeach(ext ${extensions_nocat})
# Tests 108-110
# 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_3})
foreach(ext ${extensions_nocat})
add_test(
NAME verify_ts_revoked_crldp_${ext}
COMMAND osslsigncode "verify"
@@ -560,7 +562,7 @@ if(Python3_FOUND OR server_error)
REQUIRED_FILES "${FILES}/ts_revoked_crldp.${ext}"
REQUIRED_FILES "${LOGS}/port.log"
WILL_FAIL TRUE)
endforeach(ext ${extensions_3})
endforeach(ext ${extensions_nocat})
### Cleanup ###
@@ -585,7 +587,7 @@ endif(Python3_FOUND OR server_error)
# Test 112
# Delete test files
foreach(ext ${extensions_4})
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}")
@@ -603,7 +605,7 @@ foreach(ext ${extensions_4})
endforeach(format ${formats})
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/jreq.tsq")
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/jresp.tsr")
endforeach(ext ${extensions_4})
endforeach(ext ${extensions_all})
add_test(NAME remove_files
COMMAND ${CMAKE_COMMAND} -E rm -f ${OUTPUT_FILES})
+21 -13
View File
@@ -12,7 +12,7 @@
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);
static int pkcs7_set_spc_indirect_data_content(PKCS7 *p7, BIO *hash, u_char *buf, int len, FILE_FORMAT_CTX *ctx);
static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
@@ -298,6 +298,7 @@ PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx)
/*
* [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)
@@ -471,7 +472,7 @@ int pkcs7_set_data_content(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx)
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)) {
if (!pkcs7_set_spc_indirect_data_content(p7, hash, buf, len, ctx)) {
OPENSSL_free(buf);
return 0; /* FAILED */
}
@@ -573,6 +574,7 @@ static int spc_indirect_data_content_get(u_char **blob, int *len, FILE_FORMAT_CT
{
u_char *p = NULL;
int hashlen, l = 0;
int mdtype = EVP_MD_nid(ctx->options->md);
void *hash;
SpcIndirectDataContent *idc = SpcIndirectDataContent_new();
@@ -582,13 +584,12 @@ static int spc_indirect_data_content_get(u_char **blob, int *len, FILE_FORMAT_CT
idc->data->type = ctx->format->data_blob_get(&p, &l, ctx);
idc->data->value->value.sequence->data = p;
idc->data->value->value.sequence->length = l;
idc->messageDigest->digestAlgorithm->algorithm = OBJ_nid2obj(EVP_MD_nid(ctx->options->md));
idc->messageDigest->digestAlgorithm->algorithm = OBJ_nid2obj(mdtype);
idc->messageDigest->digestAlgorithm->parameters = ASN1_TYPE_new();
idc->messageDigest->digestAlgorithm->parameters->type = V_ASN1_NULL;
hashlen = EVP_MD_size(ctx->options->md);
hash = OPENSSL_malloc((size_t)hashlen);
memset(hash, 0, (size_t)hashlen);
hashlen = ctx->format->hash_length_get(ctx);
hash = OPENSSL_zalloc((size_t)hashlen);
ASN1_OCTET_STRING_set(idc->messageDigest->digest, hash, hashlen);
OPENSSL_free(hash);
@@ -597,7 +598,7 @@ static int spc_indirect_data_content_get(u_char **blob, int *len, FILE_FORMAT_CT
p = *blob;
i2d_SpcIndirectDataContent(idc, &p);
SpcIndirectDataContent_free(idc);
*len -= EVP_MD_size(ctx->options->md);
*len -= hashlen;
return 1; /* OK */
}
@@ -607,17 +608,24 @@ static int spc_indirect_data_content_get(u_char **blob, int *len, FILE_FORMAT_CT
* [in] hash: message digest BIO
* [in] blob: SpcIndirectDataContent data
* [in] len: SpcIndirectDataContent data length
* [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)
static int pkcs7_set_spc_indirect_data_content(PKCS7 *p7, BIO *hash, u_char *buf, int len, FILE_FORMAT_CTX *ctx)
{
u_char mdbuf[EVP_MAX_MD_SIZE];
int mdlen, seqhdrlen;
u_char mdbuf[5 * EVP_MAX_MD_SIZE + 24];
int mdlen, seqhdrlen, hashlen;
BIO *bio;
PKCS7 *td7;
mdlen = BIO_gets(hash, (char*)mdbuf, EVP_MAX_MD_SIZE);
memcpy(buf+len, mdbuf, (size_t)mdlen);
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);
}
memcpy(buf + len, mdbuf, (size_t)mdlen);
seqhdrlen = asn1_simple_hdr_len(buf, len);
if ((bio = PKCS7_dataInit(p7, NULL)) == NULL) {
@@ -638,7 +646,7 @@ static int pkcs7_set_spc_indirect_data_content(PKCS7 *p7, BIO *hash, u_char *buf
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);
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");
+34 -18
View File
@@ -186,13 +186,16 @@ typedef struct {
char *ministream;
char *minifat;
char *fat;
char *difat;
uint32_t dirtreeLen;
uint32_t miniStreamLen;
uint32_t minifatLen;
uint32_t fatLen;
uint32_t difatLen;
uint32_t ministreamsMemallocCount;
uint32_t minifatMemallocCount;
uint32_t fatMemallocCount;
uint32_t difatMemallocCount;
uint32_t dirtreeSectorsCount;
uint32_t minifatSectorsCount;
uint32_t fatSectorsCount;
@@ -212,6 +215,7 @@ 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 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);
@@ -225,6 +229,7 @@ static void msi_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
FILE_FORMAT file_format_msi = {
.ctx_new = msi_ctx_new,
.data_blob_get = msi_spc_sip_info_get,
.hash_length_get = msi_hash_length_get,
.check_file = msi_check_file,
.digest_calc = msi_digest_calc,
.verify_digests = msi_verify_digests,
@@ -343,6 +348,15 @@ static ASN1_OBJECT *msi_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX
return dtype; /* 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,
* check if the signature exists.
@@ -1266,9 +1280,7 @@ static int msi_dirent_new(MSI_FILE *msi, MSI_ENTRY *entry, MSI_DIRENT *parent, M
}
/* detect cycles in previously visited entries (parents, siblings) */
if (!ret) { /* initialized (non-root entry) */
if ((entry->leftSiblingID != NOSTREAM && tortoise->entry->leftSiblingID == entry->leftSiblingID)
|| (entry->rightSiblingID != NOSTREAM && tortoise->entry->rightSiblingID == entry->rightSiblingID)
|| (entry->childID != NOSTREAM && tortoise->entry->childID == entry->childID)) {
if (!memcmp(entry, tortoise->entry, sizeof(MSI_ENTRY))) {
printf("MSI_ENTRY cycle detected at level %d\n", cnt);
OPENSSL_free(entry);
return 0; /* FAILED */
@@ -1542,6 +1554,16 @@ static void fat_append(MSI_OUT *out, char *buf, uint32_t len)
out->fatLen += len;
}
static void difat_append(MSI_OUT *out, char *buf, uint32_t len)
{
if (out->difatLen == (uint64_t)out->difatMemallocCount * out->sectorSize) {
out->difatMemallocCount += 1;
out->difat = OPENSSL_realloc(out->difat, (size_t)(out->difatMemallocCount * out->sectorSize));
}
memcpy(out->difat + out->difatLen, buf, (size_t)len);
out->difatLen += len;
}
static int msi_dirent_delete(MSI_DIRENT *dirent, const u_char *name, uint16_t nameLen)
{
int i;
@@ -1828,7 +1850,7 @@ static char *msi_dirent_get(MSI_ENTRY *entry)
return data;
}
static char *msi_unused_dirent_get()
static char *msi_unused_dirent_get(void)
{
char *data = OPENSSL_malloc(DIRENT_SIZE);
@@ -1938,25 +1960,14 @@ static void dirtree_save(MSI_DIRENT *dirent, BIO *outdata, MSI_OUT *out)
out->sectorNum += out->dirtreeSectorsCount;
}
static void fat_pad_last_sector(MSI_OUT *out, int padValue, char *buf)
{
if (out->fatLen % out->sectorSize > 0) {
uint32_t remain = out->sectorSize - out->fatLen % out->sectorSize;
memset(buf, padValue, (size_t)remain);
fat_append(out, buf, remain);
}
}
static int fat_save(BIO *outdata, MSI_OUT *out)
{
char buf[MAX_SECTOR_SIZE];
uint32_t i, j, remain, difatSectors, difatEntriesPerSector, fatSectorIndex, lastFatSectorIndex;
uint32_t i, j, remain, difatSectors, difatEntriesPerSector = 0, fatSectorIndex, lastFatSectorIndex;
remain = (out->fatLen + out->sectorSize - 1) / out->sectorSize;
out->fatSectorsCount = (out->fatLen + remain * 4 + out->sectorSize - 1) / out->sectorSize;
fat_pad_last_sector(out, 0, buf);
if (out->fatSectorsCount > DIFAT_IN_HEADER) {
difatEntriesPerSector = (out->sectorSize / 4) - 1;
difatSectors = (out->fatSectorsCount - DIFAT_IN_HEADER + difatEntriesPerSector - 1) / difatEntriesPerSector;
@@ -2001,7 +2012,7 @@ static int fat_save(BIO *outdata, MSI_OUT *out)
PUT_UINT32_LE(out->sectorNum + 1, buf + out->sectorSize - 4);
}
fat_append(out, buf, out->sectorSize);
difat_append(out, buf, out->sectorSize);
out->sectorNum++;
}
}
@@ -2019,9 +2030,14 @@ static int fat_save(BIO *outdata, MSI_OUT *out)
}
/* empty unallocated free sectors in the last FAT sector */
fat_pad_last_sector(out, (int)FREESECT, buf);
if (out->fatLen % out->sectorSize > 0) {
remain = out->sectorSize - out->fatLen % out->sectorSize;
memset(buf, (int)FREESECT, (size_t)remain);
fat_append(out, buf, remain);
}
BIO_write(outdata, out->fat, (int)out->fatLen);
BIO_write(outdata, out->difat, (int)out->difatLen);
return 1; /* OK */
}
+435 -164
View File
@@ -158,15 +158,10 @@ ASN1_SEQUENCE(CatalogAuthAttr) = {
IMPLEMENT_ASN1_FUNCTIONS(CatalogAuthAttr)
ASN1_SEQUENCE(MessageImprint) = {
ASN1_SIMPLE(MessageImprint, digestAlgorithm, AlgorithmIdentifier),
ASN1_SIMPLE(MessageImprint, digest, ASN1_OCTET_STRING)
} ASN1_SEQUENCE_END(MessageImprint)
IMPLEMENT_ASN1_FUNCTIONS(MessageImprint)
#ifdef ENABLE_CURL
/*
* Structures for Authenticode Timestamp
*/
ASN1_SEQUENCE(TimeStampRequestBlob) = {
ASN1_SIMPLE(TimeStampRequestBlob, type, ASN1_OBJECT),
ASN1_EXP_OPT(TimeStampRequestBlob, signature, ASN1_OCTET_STRING, 0)
@@ -181,59 +176,8 @@ ASN1_SEQUENCE(TimeStampRequest) = {
IMPLEMENT_ASN1_FUNCTIONS(TimeStampRequest)
/* RFC3161 Time stamping */
ASN1_SEQUENCE(PKIStatusInfo) = {
ASN1_SIMPLE(PKIStatusInfo, status, ASN1_INTEGER),
ASN1_SEQUENCE_OF_OPT(PKIStatusInfo, statusString, ASN1_UTF8STRING),
ASN1_OPT(PKIStatusInfo, failInfo, ASN1_BIT_STRING)
} ASN1_SEQUENCE_END(PKIStatusInfo)
IMPLEMENT_ASN1_FUNCTIONS(PKIStatusInfo)
ASN1_SEQUENCE(TimeStampResp) = {
ASN1_SIMPLE(TimeStampResp, status, PKIStatusInfo),
ASN1_OPT(TimeStampResp, token, PKCS7)
} ASN1_SEQUENCE_END(TimeStampResp)
IMPLEMENT_ASN1_FUNCTIONS(TimeStampResp)
ASN1_SEQUENCE(TimeStampReq) = {
ASN1_SIMPLE(TimeStampReq, version, ASN1_INTEGER),
ASN1_SIMPLE(TimeStampReq, messageImprint, MessageImprint),
ASN1_OPT (TimeStampReq, reqPolicy, ASN1_OBJECT),
ASN1_OPT (TimeStampReq, nonce, ASN1_INTEGER),
ASN1_SIMPLE(TimeStampReq, certReq, ASN1_FBOOLEAN),
ASN1_IMP_SEQUENCE_OF_OPT(TimeStampReq, extensions, X509_EXTENSION, 0)
} ASN1_SEQUENCE_END(TimeStampReq)
IMPLEMENT_ASN1_FUNCTIONS(TimeStampReq)
#endif /* ENABLE_CURL */
ASN1_SEQUENCE(TimeStampAccuracy) = {
ASN1_OPT(TimeStampAccuracy, seconds, ASN1_INTEGER),
ASN1_IMP_OPT(TimeStampAccuracy, millis, ASN1_INTEGER, 0),
ASN1_IMP_OPT(TimeStampAccuracy, micros, ASN1_INTEGER, 1)
} ASN1_SEQUENCE_END(TimeStampAccuracy)
IMPLEMENT_ASN1_FUNCTIONS(TimeStampAccuracy)
ASN1_SEQUENCE(TimeStampToken) = {
ASN1_SIMPLE(TimeStampToken, version, ASN1_INTEGER),
ASN1_SIMPLE(TimeStampToken, policy_id, ASN1_OBJECT),
ASN1_SIMPLE(TimeStampToken, messageImprint, MessageImprint),
ASN1_SIMPLE(TimeStampToken, serial, ASN1_INTEGER),
ASN1_SIMPLE(TimeStampToken, time, ASN1_GENERALIZEDTIME),
ASN1_OPT(TimeStampToken, accuracy, TimeStampAccuracy),
ASN1_OPT(TimeStampToken, ordering, ASN1_FBOOLEAN),
ASN1_OPT(TimeStampToken, nonce, ASN1_INTEGER),
ASN1_EXP_OPT(TimeStampToken, tsa, GENERAL_NAME, 0),
ASN1_IMP_SEQUENCE_OF_OPT(TimeStampToken, extensions, X509_EXTENSION, 1)
} ASN1_SEQUENCE_END(TimeStampToken)
IMPLEMENT_ASN1_FUNCTIONS(TimeStampToken)
ASN1_SEQUENCE(CatalogInfo) = {
ASN1_SIMPLE(CatalogInfo, digest, ASN1_OCTET_STRING),
ASN1_SET_OF(CatalogInfo, attributes, CatalogAuthAttr)
@@ -317,48 +261,71 @@ static BIO *bio_encode_rfc3161_request(PKCS7 *p7, const EVP_MD *md)
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
PKCS7_SIGNER_INFO *si;
u_char mdbuf[EVP_MAX_MD_SIZE];
TimeStampReq *req;
BIO *bout, *bhash;
TS_MSG_IMPRINT *msg_imprint = NULL;
X509_ALGOR *alg = NULL;
TS_REQ *req = NULL;
BIO *bout = NULL, *bhash = NULL;
u_char *p;
int len;
signer_info = PKCS7_get_signer_info(p7);
if (!signer_info)
return NULL; /* FAILED */
goto out;
si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0);
if (!si)
return NULL; /* FAILED */
goto out;
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 NULL; /* FAILED */
goto out;
}
BIO_push(bhash, BIO_new(BIO_s_null()));
BIO_write(bhash, si->enc_digest->data, si->enc_digest->length);
BIO_gets(bhash, (char*)mdbuf, EVP_MD_size(md));
BIO_free_all(bhash);
req = TimeStampReq_new();
ASN1_INTEGER_set(req->version, 1);
req->messageImprint->digestAlgorithm->algorithm = OBJ_nid2obj(EVP_MD_nid(md));
req->messageImprint->digestAlgorithm->parameters = ASN1_TYPE_new();
req->messageImprint->digestAlgorithm->parameters->type = V_ASN1_NULL;
ASN1_OCTET_STRING_set(req->messageImprint->digest, mdbuf, EVP_MD_size(md));
req->certReq = 0xFF;
req = TS_REQ_new();
if (!req)
goto out;
if (!TS_REQ_set_version(req, 1))
goto out;
len = i2d_TimeStampReq(req, NULL);
msg_imprint = TS_MSG_IMPRINT_new();
if (!msg_imprint)
goto out;
alg = X509_ALGOR_new();
if (!alg)
goto out;
X509_ALGOR_set_md(alg, md);
if (!X509_ALGOR_set0(alg, OBJ_nid2obj(EVP_MD_nid(md)), V_ASN1_NULL, NULL))
goto out;
if (!TS_MSG_IMPRINT_set_algo(msg_imprint, alg))
goto out;
if (!TS_MSG_IMPRINT_set_msg(msg_imprint, mdbuf, EVP_MD_size(md)))
goto out;
if (!TS_REQ_set_msg_imprint(req, msg_imprint))
goto out;
/* TSA is expected to include its signing certificate in the response, flag 0xFF */
if (!TS_REQ_set_cert_req(req, 1))
goto out;
len = i2d_TS_REQ(req, NULL);
p = OPENSSL_malloc((size_t)len);
len = i2d_TimeStampReq(req, &p);
len = i2d_TS_REQ(req, &p);
p -= len;
TimeStampReq_free(req);
bout = BIO_new(BIO_s_mem());
BIO_write(bout, p, len);
OPENSSL_free(p);
(void)BIO_flush(bout);
out:
BIO_free_all(bhash);
TS_MSG_IMPRINT_free(msg_imprint);
X509_ALGOR_free(alg);
TS_REQ_free(req);
return bout;
}
@@ -406,19 +373,19 @@ static BIO *bio_encode_authenticode_request(PKCS7 *p7)
}
/*
* Decode a RFC 3161 response from BIO.
* If successful the RFC 3161 timestamp will be written into
* the PKCS7 SignerInfo structure as an unauthorized attribute - cont[1].
* [in, out] p7: new PKCS#7 signature
* [in] bin: BIO with http data
* [in] response: RFC3161 response
* [in] verbose: additional output mode
* [returns] 1 on error or 0 on success
*/
static int decode_rfc3161_response(PKCS7 *p7, BIO *bin, int verbose)
static int attach_rfc3161_response(PKCS7 *p7, TS_RESP *response, int verbose)
{
PKCS7_SIGNER_INFO *si;
STACK_OF(X509_ATTRIBUTE) *attrs;
TimeStampResp *reply;
TS_STATUS_INFO *status;
PKCS7 *token;
u_char *p;
int i, len;
STACK_OF(PKCS7_SIGNER_INFO) *signer_info = PKCS7_get_signer_info(p7);
@@ -428,32 +395,31 @@ static int decode_rfc3161_response(PKCS7 *p7, BIO *bin, int verbose)
si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0);
if (!si)
return 1; /* FAILED */
reply = ASN1_item_d2i_bio(ASN1_ITEM_rptr(TimeStampResp), bin, NULL);
if (!reply || !reply->status)
if (!response)
return 1; /* FAILED */
if (ASN1_INTEGER_get(reply->status->status) != 0) {
status = TS_RESP_get_status_info(response);
if (ASN1_INTEGER_get(TS_STATUS_INFO_get0_status(status)) != 0) {
if (verbose) {
printf("Timestamping failed: status %ld\n", ASN1_INTEGER_get(reply->status->status));
for (i = 0; i < sk_ASN1_UTF8STRING_num(reply->status->statusString); i++) {
ASN1_UTF8STRING *status = sk_ASN1_UTF8STRING_value(reply->status->statusString, i);
printf("%s\n", ASN1_STRING_get0_data(status));
const STACK_OF(ASN1_UTF8STRING) *reasons = TS_STATUS_INFO_get0_text(status);
printf("Timestamping failed: status %ld\n", ASN1_INTEGER_get(TS_STATUS_INFO_get0_status(status)));
for (i = 0; i < sk_ASN1_UTF8STRING_num(reasons); i++) {
ASN1_UTF8STRING *reason = sk_ASN1_UTF8STRING_value(reasons, i);
printf("%s\n", ASN1_STRING_get0_data(reason));
}
}
TimeStampResp_free(reply);
return 1; /* FAILED */
}
if (((len = i2d_PKCS7(reply->token, NULL)) <= 0) || (p = OPENSSL_malloc((size_t)len)) == NULL) {
token = TS_RESP_get_token(response);
if (((len = i2d_PKCS7(token, NULL)) <= 0) || (p = OPENSSL_malloc((size_t)len)) == NULL) {
if (verbose) {
printf("Failed to convert pkcs7: %d\n", len);
ERR_print_errors_fp(stdout);
}
TimeStampResp_free(reply);
return 1; /* FAILED */
}
len = i2d_PKCS7(reply->token, &p);
len = i2d_PKCS7(token, &p);
p -= len;
TimeStampResp_free(reply);
attrs = sk_X509_ATTRIBUTE_new_null();
attrs = X509at_add1_attr_by_txt(&attrs, SPC_RFC3161_OBJID, V_ASN1_SET, p, len);
@@ -465,26 +431,22 @@ static int decode_rfc3161_response(PKCS7 *p7, BIO *bin, int verbose)
}
/*
* Decode an authenticode response from BIO.
* If successful the authenticode timestamp will be written into
* the PKCS7 SignerInfo structure as an unauthorized attribute - cont[1]:
* p7->d.sign->signer_info->unauth_attr
* [in, out] p7: new PKCS#7 signature
* [in] bin: base64 BIO with http data
* [in] resp: PKCS#7 authenticode response
* [in] verbose: additional output mode
* [returns] 1 on error or 0 on success
*/
static int decode_authenticode_response(PKCS7 *p7, BIO *b64_bin, int verbose)
static int attach_authenticode_response(PKCS7 *p7, PKCS7 *resp, int verbose)
{
PKCS7 *resp;
PKCS7_SIGNER_INFO *info, *si;
STACK_OF(X509_ATTRIBUTE) *attrs;
u_char *p;
int len, i;
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
resp = d2i_PKCS7_bio(b64_bin, NULL);
if (!resp) {
return 1; /* FAILED */
}
@@ -689,15 +651,25 @@ static int add_timestamp(PKCS7 *p7, FILE_FORMAT_CTX *ctx, char *url, int rfc3161
if (bin) {
if (rfc3161) {
res = decode_rfc3161_response(p7, bin, verbose);
/* decode a RFC 3161 response from BIO */
TS_RESP *response = d2i_TS_RESP_bio(bin, NULL);
BIO_free_all(bin);
res = attach_rfc3161_response(p7, response, verbose);
TS_RESP_free(response);
} else {
BIO *b64 = BIO_new(BIO_f_base64());
/* decode an authenticode response from BIO */
PKCS7 *response;
BIO *b64, *b64_bin;
b64 = BIO_new(BIO_f_base64());
if (!blob_has_nl)
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
BIO *b64_bin = BIO_push(b64, bin);
res = decode_authenticode_response(p7, b64_bin, verbose);
b64_bin = BIO_push(b64, bin);
response = d2i_PKCS7_bio(b64_bin, NULL);
BIO_free_all(b64_bin);
res = attach_authenticode_response(p7, response, verbose);
}
if (res && verbose) {
if (http_code != -1) {
@@ -744,6 +716,240 @@ static int add_timestamp_rfc3161(PKCS7 *p7, FILE_FORMAT_CTX *ctx)
}
#endif /* ENABLE_CURL */
/*
* [in] resp_ctx: a response context that can be used for generating responses
* [in] data: unused
* [returns] hexadecimal serial number
*/
static ASN1_INTEGER *serial_cb(TS_RESP_CTX *resp_ctx, void *data)
{
int ret = 0;
uint64_t buf;
ASN1_INTEGER *serial = NULL;
/* squash unused parameter warning */
(void)data;
if (RAND_bytes((unsigned char *)&buf, sizeof buf) <= 0) {
printf("RAND_bytes failed\n");
goto out;
}
serial = ASN1_INTEGER_new();
if (!serial)
goto out;
ASN1_INTEGER_set_uint64(serial, buf);
ret = 1;
out:
if (!ret) {
TS_RESP_CTX_set_status_info(resp_ctx, TS_STATUS_REJECTION,
"Error during serial number generation.");
TS_RESP_CTX_add_failure_info(resp_ctx, TS_INFO_ADD_INFO_NOT_AVAILABLE);
ASN1_INTEGER_free(serial);
return NULL; /* FAILED */
}
return serial;
}
/*
* This must return the seconds and microseconds since Jan 1, 1970 in the sec
* and usec variables allocated by the caller.
* [in] resp_ctx: a response context that can be used for generating responses
* [in] data: timestamping time
* [out] sec: total of seconds since Jan 1, 1970
* [out] usec: microseconds (unused)
* [returns] 0 on error or 1 on success
*/
static int time_cb(TS_RESP_CTX *resp_ctx, void *data, long *sec, long *usec)
{
time_t *time = (time_t *)data;
if(!*time) {
TS_RESP_CTX_set_status_info(resp_ctx, TS_STATUS_REJECTION,
"Time is not available.");
TS_RESP_CTX_add_failure_info(resp_ctx, TS_INFO_TIME_NOT_AVAILABLE);
return 0; /* FAILED */
}
*sec = (long int)*time;
*usec = 0;
return 1; /* OK */
}
/*
* [in] ctx: structure holds input and output data
* [in] signer_cert: the signer certificate of the TSA in PEM format
* [in] signer_key: the private key of the TSA in PEM format
* [in] chain: the certificate chain that will all be included in the response
* [in] bout: timestamp request
* [returns] RFC3161 response
*/
static TS_RESP *get_rfc3161_response(FILE_FORMAT_CTX *ctx, X509 *signer_cert,
EVP_PKEY *signer_key, STACK_OF(X509) *chain, BIO *bout)
{
TS_RESP_CTX *resp_ctx = NULL;
TS_RESP *response = NULL;
ASN1_OBJECT *policy_obj = NULL;
resp_ctx = TS_RESP_CTX_new();
if (!resp_ctx)
goto out;
TS_RESP_CTX_set_serial_cb(resp_ctx, serial_cb, NULL);
if (!TS_RESP_CTX_set_signer_cert(resp_ctx, signer_cert)) {
goto out;
}
if (!TS_RESP_CTX_set_signer_key(resp_ctx, signer_key)) {
goto out;
}
if (!TS_RESP_CTX_set_certs(resp_ctx, chain)) {
goto out;
}
/* message digest algorithm that the TSA accepts */
if (!TS_RESP_CTX_add_md(resp_ctx, ctx->options->md)) {
goto out;
}
/* signing digest to use */
if (!TS_RESP_CTX_set_signer_digest(resp_ctx, ctx->options->md)) {
goto out;
}
/* default policy to use when the request does not mandate any policy
* tsa_policy1 = 1.2.3.4.1 */
policy_obj = OBJ_txt2obj(TSA_POLICY1, 0);
if (!policy_obj) {
goto out;
}
if (!TS_RESP_CTX_set_def_policy(resp_ctx, policy_obj)) {
goto out;
}
/* the accuracy of the time source of the TSA in seconds, milliseconds
* and microseconds; e.g. secs:1, millisecs:500, microsecs:100;
* 0 means not specified */
if (!TS_RESP_CTX_set_accuracy(resp_ctx, 1, 500, 100)) {
goto out;
}
if (ctx->options->tsa_time) {
TS_RESP_CTX_set_time_cb(resp_ctx, time_cb, &(ctx->options->tsa_time));
}
/* generate RFC3161 response with embedded TS_TST_INFO structure */
response = TS_RESP_create_response(resp_ctx, bout);
if (!response) {
printf("Failed to create RFC3161 response\n");
}
out:
ASN1_OBJECT_free(policy_obj);
TS_RESP_CTX_free(resp_ctx);
return response;
}
/*
* [in] bin: certfile BIO
* [in] certpass: NULL
* [returns] pointer to STACK_OF(X509) structure
*/
static STACK_OF(X509) *X509_chain_read_certs(BIO *bin, char *certpass)
{
STACK_OF(X509) *certs = sk_X509_new_null();
X509 *x509;
(void)BIO_seek(bin, 0);
x509 = PEM_read_bio_X509(bin, NULL, NULL, certpass);
while (x509) {
sk_X509_push(certs, x509);
x509 = PEM_read_bio_X509(bin, NULL, NULL, certpass);
}
ERR_clear_error();
if (!sk_X509_num(certs)) {
sk_X509_free(certs);
return NULL;
}
return certs;
}
/*
* [in, out] p7: new PKCS#7 signature
* [in] ctx: structure holds input and output data
* [returns] 1 on error or 0 on success
*/
static int add_timestamp_builtin(PKCS7 *p7, FILE_FORMAT_CTX *ctx)
{
BIO *btmp, *bout;
STACK_OF(X509) *chain;
X509 *signer_cert = NULL;
EVP_PKEY *signer_key;
TS_RESP *response = NULL;
int i, res = 1;
btmp = BIO_new_file(ctx->options->tsa_certfile, "rb");
if (!btmp) {
printf("Failed to read Time-Stamp Authority certificate file: %s\n", ctx->options->tsa_certfile);
return 0; /* FAILED */
}
/* .pem certificate file */
chain = X509_chain_read_certs(btmp, NULL);
BIO_free(btmp);
btmp = BIO_new_file(ctx->options->tsa_keyfile, "rb");
if (!btmp) {
printf("Failed to read private key file: %s\n", ctx->options->tsa_keyfile);
return 0; /* FAILED */
}
signer_key = PEM_read_bio_PrivateKey(btmp, NULL, NULL, NULL);
BIO_free(btmp);
if(!chain || !signer_key) {
printf("Failed to load Time-Stamp Authority crypto parameters\n");
return 0; /* FAILED */
}
/* find the signer's certificate located somewhere in the whole certificate chain */
for (i=0; i<sk_X509_num(chain); i++) {
X509 *cert = sk_X509_value(chain, i);
if (X509_check_private_key(cert, signer_key)) {
signer_cert = cert;
break;
}
}
if(!signer_cert) {
printf("Failed to checking the consistency of a TSA private key with a public key in any X509 certificate\n");
goto out;
}
/* The TSA signing certificate must have exactly one extended key usage
* assigned to it: timeStamping. The extended key usage must also be critical,
* otherwise the certificate is going to be refused. */
/* check X509_PURPOSE_TIMESTAMP_SIGN certificate purpose */
if (X509_check_purpose(signer_cert, X509_PURPOSE_TIMESTAMP_SIGN, 0) != 1) {
printf("Unsupported TSA signer's certificate purpose X509_PURPOSE_TIMESTAMP_SIGN\n");
goto out;
}
/* check extended key usage flag XKU_TIMESTAMP */
if (!(X509_get_extended_key_usage(signer_cert) & XKU_TIMESTAMP)) {
printf("Unsupported Signer's certificate purpose XKU_TIMESTAMP\n");
goto out;
}
/* encode timestamp request */
bout = bio_encode_rfc3161_request(p7, ctx->options->md);
if (!bout) {
printf("Failed to encode timestamp request\n");
goto out;
}
response = get_rfc3161_response(ctx, signer_cert, signer_key, chain, bout);
BIO_free_all(bout);
if (response) {
res = attach_rfc3161_response(p7, response, ctx->options->verbose);
if (res) {
printf("Failed to convert timestamp reply\n");
ERR_print_errors_fp(stdout);
}
} else {
printf("Failed to obtain RFC3161 response\n");
}
out:
sk_X509_pop_free(chain, X509_free);
EVP_PKEY_free(signer_key);
TS_RESP_free(response);
return res;
}
/*
* If successful the unauthenticated blob will be written into
* the PKCS7 SignerInfo structure as an unauthorized attribute - cont[1]:
@@ -801,6 +1007,10 @@ static int add_timestamp_and_blob(PKCS7 *p7, FILE_FORMAT_CTX *ctx)
"Use the \"-t\" option to add the Authenticode Time-Stamp Authority or choose another one RFC3161 Time-Stamp Authority");
return 1; /* FAILED */
}
if (ctx->options->tsa_certfile && ctx->options->tsa_keyfile && add_timestamp_builtin(p7, ctx)) {
printf("Built-in timestamping failed\n");
return 1; /* FAILED */
}
#endif /* ENABLE_CURL */
if (ctx->options->addBlob && !add_unauthenticated_blob(p7)) {
printf("Adding unauthenticated blob failed\n");
@@ -1224,6 +1434,20 @@ static STACK_OF(X509_CRL) *x509_crl_list_get(PKCS7 *p7, X509_CRL *crl)
return crls;
}
static void print_timestamp_serial_number(TS_TST_INFO *token)
{
BIGNUM *serialbn;
char *number;
if (!token)
return;
serialbn = ASN1_INTEGER_to_BN(TS_TST_INFO_get_serial(token), NULL);
number = BN_bn2hex(serialbn);
printf("Timestamp serial number: %s\n", number);
BN_free(serialbn);
OPENSSL_free(number);
}
/*
* Compare the hash provided from the TSTInfo object against the hash computed
* from the signature created by the signing certificate's private key
@@ -1235,35 +1459,42 @@ static int verify_timestamp_token(PKCS7 *p7, CMS_ContentInfo *timestamp)
{
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
PKCS7_SIGNER_INFO *si;
ASN1_OCTET_STRING *hash, **pos;
TimeStampToken *token = NULL;
const u_char *p = NULL;
u_char mdbuf[EVP_MAX_MD_SIZE];
const EVP_MD *md;
int md_nid;
BIO *bhash;
ASN1_OCTET_STRING **pos;
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 */
/* get the embedded content */
pos = CMS_get0_content(timestamp);
if (pos != NULL && *pos != NULL) {
p = (*pos)->data;
token = d2i_TimeStampToken(NULL, &p, (*pos)->length);
const u_char *p = (*pos)->data;
TS_TST_INFO *token = d2i_TS_TST_INFO(NULL, &p, (*pos)->length);
if (token) {
/* compute a hash from the encrypted message digest value of the file */
md_nid = OBJ_obj2nid(token->messageImprint->digestAlgorithm->algorithm);
BIO *bhash;
u_char mdbuf[EVP_MAX_MD_SIZE];
ASN1_OCTET_STRING *hash;
const ASN1_OBJECT *aoid;
int md_nid;
const EVP_MD *md;
TS_MSG_IMPRINT *msg_imprint = TS_TST_INFO_get_msg_imprint(token);
const X509_ALGOR *alg = TS_MSG_IMPRINT_get_algo(msg_imprint);
X509_ALGOR_get0(&aoid, NULL, NULL, alg);
md_nid = OBJ_obj2nid(aoid);
md = EVP_get_digestbynid(md_nid);
/* compute a hash from the encrypted message digest value of the file */
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 */
TS_TST_INFO_free(token);
return 0; /* FAILED */
}
BIO_push(bhash, BIO_new(BIO_s_null()));
BIO_write(bhash, si->enc_digest->data, si->enc_digest->length);
@@ -1271,23 +1502,25 @@ static int verify_timestamp_token(PKCS7 *p7, CMS_ContentInfo *timestamp)
BIO_free_all(bhash);
/* compare the provided hash against the computed hash */
hash = token->messageImprint->digest;
/* hash->length == EVP_MD_size(md) */
hash =TS_MSG_IMPRINT_get_msg(msg_imprint);
if (memcmp(mdbuf, hash->data, (size_t)hash->length)) {
printf("Hash value mismatch:\n\tMessage digest algorithm: %s\n",
(md_nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(md_nid));
print_hash("\tComputed message digest", "", mdbuf, EVP_MD_size(md));
print_hash("\tReceived message digest", "", hash->data, hash->length);
printf("\nFile's message digest verification: failed\n");
TimeStampToken_free(token);
TS_TST_INFO_free(token);
return 0; /* FAILED */
} /* else Computed and received message digests matched */
TimeStampToken_free(token);
print_timestamp_serial_number(token);
TS_TST_INFO_free(token);
} else
/* our CMS_ContentInfo struct created for Authenticode Timestamp
* does not contain any TimeStampToken as specified in RFC 3161 */
* does not contain any TS_TST_INFO struct as specified in RFC 3161 */
ERR_clear_error();
}
return 1; /* OK */
}
@@ -1353,8 +1586,7 @@ static int verify_timestamp(FILE_FORMAT_CTX *ctx, PKCS7 *p7, CMS_ContentInfo *ti
crl = x509_crl_get(url);
OPENSSL_free(url);
if (!crl && !ctx->options->tsa_crlfile) {
printf("Use the \"-TSA-CRLfile\" option to add one or more Time-Stamp Authority CRLs in PEM format.\n\n");
goto out;
printf("Use the \"-TSA-CRLfile\" option to add one or more Time-Stamp Authority CRLs in PEM format.\n");
}
}
#endif /* ENABLE_CURL */
@@ -1465,7 +1697,7 @@ static int verify_authenticode(FILE_FORMAT_CTX *ctx, PKCS7 *p7, time_t time, X50
crl = x509_crl_get(url);
OPENSSL_free(url);
if (!crl && !ctx->options->crlfile) {
printf("Use the \"-CRLfile\" option to add one or more CRLs in PEM format.\n\n");
printf("Use the \"-CRLfile\" option to add one or more CRLs in PEM format.\n");
goto out;
}
}
@@ -1878,20 +2110,16 @@ static time_t time_t_get_si_time(PKCS7_SIGNER_INFO *si)
*/
static time_t time_t_get_cms_time(CMS_ContentInfo *cms)
{
ASN1_OCTET_STRING **pos;
const u_char *p = NULL;
TimeStampToken *token = NULL;
ASN1_GENERALIZEDTIME *asn1_time = NULL;
time_t posix_time = INVALID_TIME;
ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
pos = CMS_get0_content(cms);
if (pos != NULL && *pos != NULL) {
p = (*pos)->data;
token = d2i_TimeStampToken(NULL, &p, (*pos)->length);
const u_char *p = (*pos)->data;
TS_TST_INFO *token = d2i_TS_TST_INFO(NULL, &p, (*pos)->length);
if (token) {
asn1_time = token->time;
const ASN1_GENERALIZEDTIME *asn1_time = TS_TST_INFO_get_time(token);
posix_time = time_t_get_asn1_time(asn1_time);
TimeStampToken_free(token);
TS_TST_INFO_free(token);
}
}
return posix_time;
@@ -1899,7 +2127,7 @@ static time_t time_t_get_cms_time(CMS_ContentInfo *cms)
/*
* Create new CMS_ContentInfo struct for Authenticode Timestamp.
* This struct does not contain any TimeStampToken as specified in RFC 3161.
* This struct does not contain any TS_TST_INFO as specified in RFC 3161.
* [in] p7_signed: PKCS#7 signedData structure
* [in] countersignature: Authenticode Timestamp decoded to PKCS7_SIGNER_INFO
* [returns] pointer to CMS_ContentInfo structure
@@ -2002,6 +2230,10 @@ static int verify_member(FILE_FORMAT_CTX *ctx, CatalogAuthAttr *attribute)
printf("Failed to extract current message digest\n\n");
return 1; /* FAILED */
}
if (!ctx->format->digest_calc) {
printf("Unsupported method: digest_calc\n");
return 1; /* FAILED */
}
md = EVP_get_digestbynid(mdtype);
cmdbuf = ctx->format->digest_calc(ctx, md);
if (!cmdbuf) {
@@ -2038,6 +2270,7 @@ static int verify_member(FILE_FORMAT_CTX *ctx, CatalogAuthAttr *attribute)
static int verify_content(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
{
ASN1_STRING *value;
ASN1_OBJECT *indir_objid;
const u_char *data;
MsCtlContent *ctlc;
int i, j;
@@ -2053,7 +2286,7 @@ static int verify_content(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
printf("Failed to extract MS_CTL_OBJID data\n");
return 1; /* FAILED */
}
ASN1_OBJECT *indir_objid = OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1);
indir_objid = OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1);
for (i = 0; i < sk_CatalogInfo_num(ctlc->header_attributes); i++) {
STACK_OF(CatalogAuthAttr) *attributes;
CatalogInfo *header_attr = sk_CatalogInfo_value(ctlc->header_attributes, i);
@@ -2220,6 +2453,11 @@ static int verify_signed_file(FILE_FORMAT_CTX *ctx, GLOBAL_OPTIONS *options)
STACK_OF(PKCS7) *signatures;
int detached = options->catalog ? 1 : 0;
if (!ctx->format->check_file) {
printf("Unsupported method: check_file\n");
return 1; /* FAILED */
}
if (!ctx->format->check_file(ctx, detached))
return 1; /* FAILED */
@@ -2238,10 +2476,18 @@ static int verify_signed_file(FILE_FORMAT_CTX *ctx, GLOBAL_OPTIONS *options)
printf("CAT file initialization error\n");
return 1; /* Failed */
}
if (!cat_ctx->format->pkcs7_extract) {
printf("Unsupported command: extract-signature\n");
return 1; /* FAILED */
}
p7 = cat_ctx->format->pkcs7_extract(cat_ctx);
cat_ctx->format->ctx_cleanup(cat_ctx, NULL, NULL);
OPENSSL_free(cat_options);
} else {
if (!ctx->format->pkcs7_extract) {
printf("Unsupported command: extract-signature\n");
return 1; /* FAILED */
}
p7 = ctx->format->pkcs7_extract(ctx);
}
if (!p7) {
@@ -2262,9 +2508,14 @@ static int verify_signed_file(FILE_FORMAT_CTX *ctx, GLOBAL_OPTIONS *options)
} else {
printf("Catalog verification: failed\n\n");
}
} else if (ctx->format->verify_digests(ctx, sig)) {
printf("Signature Index: %d %s\n", i, i==0 ? " (Primary Signature)" : "");
ret &= verify_signature(ctx, sig);
} else if (ctx->format->verify_digests) {
if (ctx->format->verify_digests(ctx, sig)) {
printf("Signature Index: %d %s\n", i, i==0 ? " (Primary Signature)" : "");
ret &= verify_signature(ctx, sig);
}
} else {
printf("Unsupported method: verify_digests\n");
return 1; /* FAILED */
}
}
printf("Number of verified signatures: %d\n", i);
@@ -2320,6 +2571,8 @@ static int check_attached_data(GLOBAL_OPTIONS *options)
ctx = file_format_pe.ctx_new(tmp_options, NULL, NULL);
if (!ctx)
ctx = file_format_cab.ctx_new(tmp_options, NULL, NULL);
if (!ctx)
ctx = file_format_appx.ctx_new(tmp_options, NULL, NULL);
if (!ctx)
ctx = file_format_cat.ctx_new(tmp_options, NULL, NULL);
if (!ctx) {
@@ -2419,6 +2672,8 @@ static void usage(const char *argv0, const char *cmd)
printf("%12s[ -t <timestampurl> [ -t ... ] [ -p <proxy> ] [ -noverifypeer ]\n", "");
printf("%12s[ -ts <timestampurl> [ -ts ... ] [ -p <proxy> ] [ -noverifypeer ] ]\n", "");
#endif /* ENABLE_CURL */
printf("%12s[ -TSA-certs <TSA-certfile> ] [ -TSA-key <TSA-keyfile> ]\n", "");
printf("%12s[ -TSA-time <unix-time> ]\n", "");
printf("%12s[ -time <unix-time> ]\n", "");
printf("%12s[ -addUnauthenticatedBlob ]\n", "");
printf("%12s[ -nest ]\n", "");
@@ -2432,6 +2687,8 @@ static void usage(const char *argv0, const char *cmd)
printf("%12s[ -t <timestampurl> [ -t ... ] [ -p <proxy> ] [ -noverifypeer ]\n", "");
printf("%12s[ -ts <timestampurl> [ -ts ... ] [ -p <proxy> ] [ -noverifypeer ] ]\n", "");
#endif /* ENABLE_CURL */
printf("%12s[ -TSA-certs <TSA-certfile> ] [ -TSA-key <TSA-keyfile> ]\n", "");
printf("%12s[ -TSA-time <unix-time> ]\n", "");
printf("%12s[ -h {md5,sha1,sha2(56),sha384,sha512} ]\n", "");
printf("%12s[ -verbose ]\n", "");
printf("%12s[ -add-msi-dse ]\n", "");
@@ -2529,6 +2786,9 @@ static void help_for(const char *argv0, const char *cmd)
const char *cmds_ts[] = {"add", "sign", NULL};
#endif /* ENABLE_CURL */
const char *cmds_CAfileTSA[] = {"attach-signature", "verify", NULL};
const char *cmds_certsTSA[] = {"add", "sign", NULL};
const char *cmds_keyTSA[] = {"add", "sign", NULL};
const char *cmds_timeTSA[] = {"add", "sign", NULL};
const char *cmds_verbose[] = {"add", "sign", "verify", NULL};
if (on_list(cmd, cmds_all)) {
@@ -2678,34 +2938,17 @@ static void help_for(const char *argv0, const char *cmd)
printf("%-24s= the file containing one or more Time-Stamp Authority certificates in PEM format\n", "-TSA-CAfile");
if (on_list(cmd, cmds_CRLfileTSA))
printf("%-24s= the file containing one or more Time-Stamp Authority CRLs in PEM format\n", "-TSA-CRLfile");
if (on_list(cmd, cmds_certsTSA))
printf("%-24s= Time-Stamp Authority signing certificate\n", "-TSA-certs");
if (on_list(cmd, cmds_keyTSA))
printf("%-24s= Time-Stamp Authority private key or PKCS#11 URI identifies a key in the token\n", "-TSA-key");
if (on_list(cmd, cmds_timeTSA))
printf("%-24s= the unix-time to set the Time-Stamp Authority signing\n", "-TSA-time");
if (on_list(cmd, cmds_verbose))
printf("%-24s= include additional output in the log\n", "-verbose");
usage(argv0, cmd);
}
/*
* [in] bin: certfile BIO
* [in] certpass: NULL
* [returns] pointer to STACK_OF(X509) structure
*/
static STACK_OF(X509) *X509_chain_read_certs(BIO *bin, char *certpass)
{
STACK_OF(X509) *certs = sk_X509_new_null();
X509 *x509;
(void)BIO_seek(bin, 0);
x509 = PEM_read_bio_X509(bin, NULL, NULL, certpass);
while (x509) {
sk_X509_push(certs, x509);
x509 = PEM_read_bio_X509(bin, NULL, NULL, certpass);
}
ERR_clear_error();
if (!sk_X509_num(certs)) {
sk_X509_free(certs);
return NULL;
}
return certs;
}
#ifdef PROVIDE_ASKPASS
/*
* [in] prompt: "Password: "
@@ -3091,7 +3334,7 @@ static ENGINE *engine_dynamic(GLOBAL_OPTIONS *options)
* [in] none
* [returns] pointer to ENGINE
*/
static ENGINE *engine_pkcs11()
static ENGINE *engine_pkcs11(void)
{
ENGINE *engine = ENGINE_by_id("pkcs11");
if (!engine) {
@@ -3586,6 +3829,24 @@ static int main_configure(int argc, char **argv, GLOBAL_OPTIONS *options)
return 0; /* FAILED */
}
options->leafhash = (*++argv);
} else if ((cmd == CMD_SIGN || cmd == CMD_ADD) && !strcmp(*argv, "-TSA-certs")) {
if (--argc < 1) {
usage(argv0, "all");
return 0; /* FAILED */
}
options->tsa_certfile = *(++argv);
} else if ((cmd == CMD_SIGN || cmd == CMD_ADD) && !strcmp(*argv, "-TSA-key")) {
if (--argc < 1) {
usage(argv0, "all");
return 0; /* FAILED */
}
options->tsa_keyfile = *(++argv);
} else if ((cmd == CMD_SIGN || cmd == CMD_ADD) && !strcmp(*argv, "-TSA-time")) {
if (--argc < 1) {
usage(argv0, "all");
return 0; /* FAILED */
}
options->tsa_time = (time_t)strtoull(*(++argv), NULL, 10);
} else if ((cmd == CMD_ADD) && !strcmp(*argv, "--help")) {
help_for(argv0, "add");
cmd = CMD_HELP;
@@ -3651,6 +3912,8 @@ static int main_configure(int argc, char **argv, GLOBAL_OPTIONS *options)
if (argc > 0 ||
#ifdef ENABLE_CURL
(options->nturl && options->ntsurl) ||
(options->nturl && options->tsa_certfile && options->tsa_keyfile) ||
(options->ntsurl && options->tsa_certfile && options->tsa_keyfile) ||
#endif
!options->infile ||
(cmd != CMD_VERIFY && !options->outfile) ||
@@ -3733,6 +3996,8 @@ int main(int argc, char **argv)
ctx = file_format_pe.ctx_new(&options, hash, outdata);
if (!ctx)
ctx = file_format_cab.ctx_new(&options, hash, outdata);
if (!ctx)
ctx = file_format_appx.ctx_new(&options, hash, outdata);
if (!ctx)
ctx = file_format_cat.ctx_new(&options, hash, outdata);
if (!ctx) {
@@ -3744,7 +4009,10 @@ int main(int argc, char **argv)
if (options.cmd == CMD_VERIFY) {
ret = verify_signed_file(ctx, &options);
goto skip_signing;
} else if (options.cmd == CMD_EXTRACT && ctx->format->pkcs7_extract) {
} else if (options.cmd == CMD_EXTRACT) {
if (!ctx->format->pkcs7_extract) {
DO_EXIT_0("Unsupported command: extract-signature\n");
}
p7 = ctx->format->pkcs7_extract(ctx);
if (!p7) {
DO_EXIT_0("Unable to extract existing signature\n");
@@ -3752,7 +4020,10 @@ int main(int argc, char **argv)
ret = save_extracted_pkcs7(ctx, outdata, p7);
PKCS7_free(p7);
goto skip_signing;
} else if (options.cmd == CMD_REMOVE && ctx->format->remove_pkcs7) {
} else if (options.cmd == CMD_REMOVE) {
if (!ctx->format->remove_pkcs7) {
DO_EXIT_0("Unsupported command: remove-signature\n");
}
ret = ctx->format->remove_pkcs7(ctx, hash, outdata);
if (ctx->format->update_data_size) {
ctx->format->update_data_size(ctx, outdata, NULL);
+12
View File
@@ -60,7 +60,9 @@
#if OPENSSL_VERSION_NUMBER>=0x30000000L
#include <openssl/provider.h>
#endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */
#include <openssl/rand.h>
#include <openssl/safestack.h>
#include <openssl/ts.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h> /* X509_PURPOSE */
@@ -210,6 +212,9 @@
#define DO_EXIT_1(x, y) { printf(x, y); goto err_cleanup; }
#define DO_EXIT_2(x, y, z) { printf(x, y, z); goto err_cleanup; }
/* Default policy if request did not specify it. */
#define TSA_POLICY1 "1.2.3.4.1"
typedef enum {
CMD_SIGN,
CMD_EXTRACT,
@@ -278,6 +283,9 @@ typedef struct {
cmd_type_t cmd;
char *indata;
PKCS7 *prevsig;
char *tsa_certfile;
char *tsa_keyfile;
time_t tsa_time;
} GLOBAL_OPTIONS;
/*
@@ -458,6 +466,7 @@ typedef struct msi_ctx_st MSI_CTX;
typedef struct pe_ctx_st PE_CTX;
typedef struct cab_ctx_st CAB_CTX;
typedef struct cat_ctx_st CAT_CTX;
typedef struct appx_ctx_st APPX_CTX;
typedef struct {
FILE_FORMAT *format;
@@ -467,6 +476,7 @@ typedef struct {
PE_CTX *pe_ctx;
CAB_CTX *cab_ctx;
CAT_CTX *cat_ctx;
APPX_CTX *appx_ctx;
};
} FILE_FORMAT_CTX;
@@ -474,10 +484,12 @@ extern FILE_FORMAT file_format_msi;
extern FILE_FORMAT file_format_pe;
extern FILE_FORMAT file_format_cab;
extern FILE_FORMAT file_format_cat;
extern FILE_FORMAT file_format_appx;
struct file_format_st {
FILE_FORMAT_CTX *(*ctx_new) (GLOBAL_OPTIONS *option, BIO *hash, BIO *outdata);
ASN1_OBJECT *(*data_blob_get) (u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
int (*hash_length_get) (FILE_FORMAT_CTX *ctx);
int (*check_file) (FILE_FORMAT_CTX *ctx, int detached);
u_char *(*digest_calc) (FILE_FORMAT_CTX *ctx, const EVP_MD *md);
int (*verify_digests) (FILE_FORMAT_CTX *ctx, PKCS7 *p7);
+12 -1
View File
@@ -44,6 +44,7 @@ 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 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);
@@ -59,6 +60,7 @@ static void pe_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
FILE_FORMAT file_format_pe = {
.ctx_new = pe_ctx_new,
.data_blob_get = pe_spc_image_data_get,
.hash_length_get = pe_hash_length_get,
.check_file = pe_check_file,
.digest_calc = pe_digest_calc,
.verify_digests = pe_verify_digests,
@@ -168,6 +170,15 @@ static ASN1_OBJECT *pe_spc_image_data_get(u_char **p, int *plen, FILE_FORMAT_CTX
return dtype; /* 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 pe_hash_length_get(FILE_FORMAT_CTX *ctx)
{
return EVP_MD_size(ctx->options->md);
}
/*
* Print current and calculated PE checksum,
* check if the signature exists.
@@ -919,7 +930,7 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
/* NumberOfSections indicates the size of the section table,
* which immediately follows the headers, can be up to 65535 under Vista and later */
nsections = GET_UINT16_LE(ctx->options->indata + ctx->pe_ctx->header_size + 6);
if (nsections == 0 || nsections > UINT16_MAX) {
if (nsections == 0) {
printf("Corrupted number of sections: 0x%08X\n", nsections);
return NULL; /* FAILED */
}
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.