mirror of
https://github.com/mtrojnar/osslsigncode.git
synced 2025-07-02 19:22:47 -05:00
Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
9ebd79ad18 | |||
1700455533 | |||
a6f767f5a3 | |||
4c5b329bc4 | |||
5626482e82 | |||
2d21a2121c | |||
5d2bf2c80f | |||
5b8376ce32 | |||
1fc2c937f2 | |||
2ed54490a6 | |||
a096aa8a33 | |||
aa08566a63 | |||
c04b229ce2 | |||
adcfd9a33f | |||
f2f3a8891c | |||
29eedf9059 | |||
d6f94d71f7 | |||
a509a66c65 | |||
7bf4c92d83 |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -7,7 +7,7 @@ on:
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
BUILD_TYPE: Release
|
||||
version: osslsigncode-2.6-dev
|
||||
version: osslsigncode-2.7
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
2
.github/workflows/coverity.yml
vendored
2
.github/workflows/coverity.yml
vendored
@ -2,7 +2,7 @@ name: Coverity Scan
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
coverity:
|
||||
|
@ -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
NEWS.md
9
NEWS.md
@ -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
|
||||
|
@ -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
|
||||
|
12
cab.c
12
cab.c
@ -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);
|
||||
|
2
cat.c
2
cat.c
@ -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)
|
||||
|
@ -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})
|
||||
|
34
helpers.c
34
helpers.c
@ -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");
|
||||
|
52
msi.c
52
msi.c
@ -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 */
|
||||
}
|
||||
|
||||
|
599
osslsigncode.c
599
osslsigncode.c
@ -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);
|
||||
|
@ -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);
|
||||
|
13
pe.c
13
pe.c
@ -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
tests/files/unsigned.256appx
Executable file
BIN
tests/files/unsigned.256appx
Executable file
Binary file not shown.
BIN
tests/files/unsigned.512appx
Executable file
BIN
tests/files/unsigned.512appx
Executable file
Binary file not shown.
Reference in New Issue
Block a user