32 Commits

Author SHA1 Message Date
Michał Trojnara 97a9ade6ec Release 2.13
Signed-off-by: Michał Trojnara <Michal.Trojnara@stunnel.org>
2026-02-10 22:51:25 +01:00
Michał Trojnara f2f33bb131 Move providers_cleanup() back 2026-02-10 19:10:00 +01:00
Michał Trojnara 202b2c2866 Separate OpenSSL and functional initialization 2026-02-10 18:37:48 +01:00
olszomal 2a5409b7c4 Fix header bounds validation in PE page hash calculation 2026-02-09 16:15:21 +01:00
olszomal 87bce8e372 Fix memory leaks on error paths in PE signing 2026-02-09 16:15:21 +01:00
olszomal f7ace57c81 Validate PE attribute certificate table bounds 2026-02-09 16:15:21 +01:00
olszomal 92f8761b47 Fix heap corruption in PE page hash calculation 2026-02-06 15:41:01 +01:00
Antoni Klajn 09d3312fd9 Fixed integer overflow, integer underflow and Out-of-Bounds Read 2026-02-06 11:39:49 +01:00
olszomal 9d02a20aec Fix unsafe ZIP size handling and allocation checks 2026-02-04 10:13:03 +01:00
olszomal f190ec5d87 Fix double free in ZIP local header 2026-02-04 10:13:03 +01:00
Michał Trojnara 4b30d6be28 Initial 2.12-dev commit 2026-02-03 17:20:29 +01:00
Michał Trojnara fac8164622 Release 2.12
Signed-off-by: Michał Trojnara <Michal.Trojnara@stunnel.org>
2026-02-02 17:53:25 +01:00
Michał Trojnara cbee1e723c Fixed buffer overflow while extracting msg digest
Reported and fixed by Antoni Klajn, Opera
2026-02-02 17:37:45 +01:00
Michał Trojnara f90327df09 Initial 2.12-dev commit 2026-01-21 00:08:58 +01:00
Michał Trojnara f3a590be69 Release 2.11
Signed-off-by: Michał Trojnara <Michal.Trojnara@stunnel.org>
2026-01-20 23:53:33 +01:00
Michał Trojnara 6631a5f10b Update trusted certificate list 2026-01-20 23:21:33 +01:00
Michał Trojnara 9924f0c085 Minor style improvements
- Reorder checks by corresponding RFC 5280 section numbers.
- Simplify comments.
2026-01-20 23:21:33 +01:00
olszomal 7d85ac5f04 Add GitHub issue and PR templates 2026-01-09 14:41:02 +01:00
olszomal feebbcd4d9 Print current CRL during certificate verification 2026-01-07 13:36:43 +01:00
olszomal d787541107 tests: add digitalSignature keyUsage to leaf certificate 2025-12-31 11:38:21 +01:00
olszomal 6390ae2746 Add keyUsage digitalSignature validation for signer certificate 2025-12-31 11:38:21 +01:00
Michał Trojnara a472d7fbff Comment returned CRL Content-Type 2025-12-22 19:26:21 +01:00
Chris Thibodeaux 27172a07ca Patch CRL fetch failure from expected file type
`application/octet-stream` response types caused CRL/TSA-CRL fetch failures
2025-12-22 19:22:01 +01:00
olszomal d77ddb9443 Disable keep-alive and remove the shutdown workaround.
Some RFC 3161 TSA servers (e.g. time.certum.pl) advertise
"Connection: close" but delay closing the connection,
when keep-alive was requested. The client waited for EOF and
attempted to work around this by explicitly shutting down the socket.
2025-12-19 15:11:12 +01:00
olszomal 988f72249b Simplify ASLR/PIE flags check for macOS 2025-12-16 06:42:01 +01:00
olszomal c23f92ca68 Improve PKCS#11 and CNG usage instructions in README 2025-09-22 11:16:29 +02:00
olszomal 842bd94aaf Remove duplicate certs from sorted X509 chain 2025-09-19 17:02:21 +02:00
olszomal 1d72c3da8c Improve key/cert loading logic and standardize usage file argument names 2025-09-19 17:02:21 +02:00
olszomal d792e8d0db Use bio_new_file() wrapper instead of BIO_new_file() for consistent file handling 2025-09-19 17:01:02 +02:00
olszomal bbdfc1d98a Avoid undefined behavior with BIO_get_fp by replacing BIO_new_file with fopen + BIO_new_fp 2025-09-19 17:01:02 +02:00
olszomal 5ac11e9f58 Fix -Wsign-conversion warning in x509_name_to_utf8() 2025-07-01 12:21:44 +02:00
Michał Trojnara 55541c6ace Initial 2.11-dev commit 2025-06-23 21:42:26 +02:00
24 changed files with 2220 additions and 851 deletions
+8
View File
@@ -0,0 +1,8 @@
<!--
Please use one of the available issue templates.
Bug reports without required information may be closed.
-->
If you are reporting a bug or crash, please use the appropriate issue template.
For questions or support, use please use [Discussions](<https://github.com/mtrojnar/osslsigncode/discussions>).
+74
View File
@@ -0,0 +1,74 @@
---
name: Crash report
about: Report a segmentation fault or other crash
labels: crash
---
<!--
Thank you for your crash report.
Note: Please search to see if an issue already exists for the bug you encountered.
-->
### Segmentation Fault / Crash Details
<!--
Provide exact, reproducible steps.
Include the complete command, exactly as executed.
-->
- Signal / exit code: <!-- SIGSEGV, SIGABRT -->
- Reproducibility: <!-- always / sometimes / once -->
- Affected command or operation: <!-- e.g. `osslsigncode sign`, `osslsigncode verify` -->
- First observed version:
- Last known working version (if any):
#### Backtrace
<!--
Provide a backtrace from gdb or lldb.
Build with debug symbols if possible. Use `bt full` if possible.
Crash reports without a backtrace may be closed without investigation.
-->
- `(gdb) bt`
#### Memory / Sanitizers
<!--
Attach relevant output if available.
-->
- [ ] Valgrind
- [ ] ASan / UBSan
- [ ] Other tools
#### Crash Context
<!--
Anything that may be relevant:
- OpenSSL provider / engine in use
- PKCS#11 modules
- Custom OpenSSL configuration
- Threading or concurrency
-->
### Environment
- Operating system and version (e.g. Ubuntu 24.04):
- Architecture (x86_64, arm64, etc.):
### Versions
<!--
Please verify that the issue is reproducible with the current upstream master.
-->
- osslsigncode built from:
- [ ] upstream master
- [ ] upstream release (tag):
- [ ] distribution package (name and version):
- `openssl version -a`
- `osslsigncode --version`
### Configuration / Settings
<!--
Anything that could affect signing or verification:
- Custom OpenSSL configuration
- Engine / provider settings
- Environment variables (OPENSSL_CONF, etc.)
-->
### Anything else
<!--
Links, references, related issues, workarounds or additional observations.
-->
@@ -0,0 +1,26 @@
---
name: Documentation
about: Report an error in (or missing) documentation
labels: documentation
---
<!--
Thank you for taking the time to report a documentation issue.
-->
### Documentation Location
<!--
Where is the problem located?
Provide a link, file path, or section name.
-->
### Issue Description
<!--
Describe what is wrong or missing.
-->
### Suggested Improvement (optional)
<!--
If you know how it should be fixed, describe it here.
Proposed wording or examples are especially helpful.
-->
@@ -0,0 +1,30 @@
---
name: Feature request
about: Suggest a new feature or improvement
labels: feature
---
<!--
Thank you for your feature request.
Please describe the use case and motivation as clearly as possible.
-->
### Use Case / Motivation
<!--
What problem are you trying to solve?
Why is this feature needed?
-->
### Proposed Change
<!--
Describe the feature or improvement you are proposing.
High-level description is sufficient.
-->
### Additional Notes (optional)
<!--
Anything else that may help:
- examples
- references
- related issues
-->
+17
View File
@@ -0,0 +1,17 @@
---
name: Questions / Support
about: Please use Q&A in Discussions instead
labels: question
---
### Questions and Support
Please do **not** use GitHub issues for general questions or support requests.
For:
- usage questions
- "how do I..." questions
please use [Q&A category in Discussions](<https://github.com/mtrojnar/osslsigncode/discussions/new?category=q-a>)
Bug reports and crashes should be reported using the appropriate issue templates.
+77
View File
@@ -0,0 +1,77 @@
---
name: Other bug report
about: Report a bug
labels: bug
---
<!--
Thank you for your bug report.
Note: Please search to see if an issue already exists for the bug you encountered.
-->
### Current Behavior
<!--
A concise description of what is happening.
Include error messages or incorrect results.
-->
### Expected Behavior
<!--
A concise description of what you expected to happen instead.
-->
### Steps To Reproduce & Observed Output
<!--
Provide exact, reproducible steps together with full stdout/stderr for each.
-->
1. Signing with osslsigncode
<!--
Full `osslsigncode sign` command and complete stdout/stderr output.
-->
2. Verification with osslsigncode
<!--
Full `osslsigncode verify` command and complete stdout/stderr output.
-->
3. Signing / verification with Windows signtool (if applicable)
<!--
Full signtool command (`signtool verify /pa /v`) and complete stdout/stderr output.
-->
### Environment
- Operating system and version (e.g. Ubuntu 24.04):
- Architecture (x86_64, arm64, etc.):
### Versions
<!--
Please verify that the issue is reproducible with the current upstream master.
-->
- osslsigncode built from:
- [ ] upstream master
- [ ] upstream release (tag):
- [ ] distribution package (name and version):
- `openssl version -a`
- `osslsigncode --version`
### Files
<!--
Attach files if possible, or mention that you will share them privately.
-->
- [ ] unsigned file
- [ ] file signed with osslsigncode
- [ ] file signed with signtool or the other tool (for comparison)
- [ ] certificate chain used for verification (PEM format)
### Configuration / Settings
<!--
Anything that could affect signing or verification:
- Custom OpenSSL configuration
- Engine / provider settings
- Environment variables (OPENSSL_CONF, etc.)
-->
### Anything else
<!--
Links, references, related issues, workarounds or additional observations.
-->
+65
View File
@@ -0,0 +1,65 @@
<!--
Thank you for your pull request.
Provide a concise summary of the changes in the PR title.
-->
### Pull Request Type
<!--
Limit this PR to a single type. If necessary, split changes into multiple PRs.
-->
- [ ] Bug fix
- [ ] New feature
- [ ] Code style / formatting / renaming
- [ ] Refactoring (no functional or API changes)
- [ ] Build / CI related changes
- [ ] Documentation
- [ ] Other (please describe):
### Related Issue
<!--
If this fixes a GitHub issue, make sure to have a line saying 'Fixes #XXXX' (without quotes) in the commit message.
-->
Issue number: N/A
### Current Behavior
<!--
Describe the current behavior or limitation this PR addresses.
Include error messages or crash symptoms if relevant.
-->
### New Behavior
<!--
Describe the new or changed behavior introduced by this PR.
-->
### Scope of Changes
<!--
Briefly describe what was changed and why.
Focus on relevant parts only.
-->
### Testing
<!--
Describe how the changes were tested.
Include commands, environments, or platforms if relevant.
-->
- [ ] Existing tests
- [ ] New tests added
- [ ] Manual testing
### Additional Notes
<!--
Any additional information relevant for reviewers:
- design decisions
- backward compatibility
- known limitations
-->
## License Declaration
<!--
All contributions to this project are licensed under the project's license.
By submitting this pull request, you confirm that you have the right to submit
the code and agree to license it accordingly.
-->
- [ ] I hereby agree to license my contribution under the project's license.
+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.10
version: osslsigncode-2.13
jobs:
build:
+1 -1
View File
@@ -10,7 +10,7 @@ set(BUILTIN_SOCKET ON CACHE BOOL "") # for static Python
# configure basic project information
project(osslsigncode
VERSION 2.10
VERSION 2.13
DESCRIPTION "OpenSSL based Authenticode signing for PE, CAB, CAT, MSI, APPX and script files"
HOMEPAGE_URL "https://github.com/mtrojnar/osslsigncode"
LANGUAGES C)
+38
View File
@@ -1,5 +1,43 @@
# osslsigncode change log
### 2.13 (2026.02.10)
**MULTIPLE SECURITY VULNERABILITIES**
This release includes important security fixes. Users are strongly encouraged
to upgrade, as the issues below may be exploitable when processing untrusted
files.
- fixed integer overflows when processing APPX compressed data streams
(by Małgorzata Olszówka)
- fixed double-free vulnerabilities in APPX file processing
(by Małgorzata Olszówka)
- fixed multiple memory corruption issues in PE page hash computation
(by Antoni Klajn (Opera) and Małgorzata Olszówka)
### 2.12 (2026.02.02)
**CRITICAL SECURITY VULNERABILITY**
This release fixes a critical memory corruption vulnerability. A malicious
attacker could create a signed file, which, when verified with osslsigncode,
triggers arbitrary code execution. Any previous version of osslsigncode should
be immediately upgraded if the tool is used for verification of untrusted
files.
- fixed a buffer overflow while extracting message digests
(reported and fixed by Antoni Klajn, Opera)
### 2.11 (2026.01.20)
- added keyUsage validation for signer certificate
(thanks to Hanqing Zhao and Zi-Quan You for reporting the issue)
- added printing CRL details during signature verification
- implemented a workaround for CRL servers returning the HTTP Content-Type
header other than application/pkix-crl (thanks to Chris Thibodeaux)
- fixed HTTP keep-alive handling
- fixed macOS compiler and linker flags
- fixed undefined BIO_get_fp() behavior with BIO_FLAGS_UPLINK_INTERNAL
### 2.10 (2025.06.23)
- added JavaScript signing
+33 -16
View File
@@ -133,8 +133,9 @@ To sign a CAB file containing Java class files:
```
Only the 'low' parameter is currently supported.
If you want to use a PKCS#11 token, you should specify the PKCS#11 engine and module.
An example of using osslsigncode with SoftHSM:
### Using the PKCS#11 Engine with osslsigncode
If you want to use a PKCS#11 token, specify the PKCS#11 engine and module.
Example usage with SoftHSM:
```
osslsigncode sign \
-engine /usr/lib64/engines-1.1/pkcs11.so \
@@ -144,8 +145,10 @@ An example of using osslsigncode with SoftHSM:
-in yourapp.exe -out yourapp-signed.exe
```
Since OpenSSL 3.0, you can use a PKCS#11 token with the PKCS#11 provider.
An example of using osslsigncode with OpenSC:
### Using the PKCS#11 Provider with osslsigncode (OpenSSL 3.x only)
OpenSSL 3.0 introduced a new provider-based architecture. To use a PKCS#11 token
with `osslsigncode`, specify the PKCS#11 provider and module.
Example usage with OpenSC:
```
osslsigncode sign \
-provider /usr/lib64/ossl-modules/pkcs11prov.so \
@@ -155,26 +158,40 @@ An example of using osslsigncode with OpenSC:
-in yourapp.exe -out yourapp-signed.exe
```
You can use a certificate and key stored in the Windows Certificate Store with
the CNG engine version 1.1 or later. For more information, refer to
### Using the CNG Engine with osslsigncode (Windows only)
The CNG engine allows using certificates and keys stored in the Windows
Certificate Store. It requires CNG engine version 1.1 or later. For more
information, refer to
https://www.stunnel.org/cng-engine.html
A non-commercial edition of CNG engine is available for testing, personal,
educational, or research purposes.
To use the CNG engine with osslsigncode, ensure that the `cng.dll` library is
placed in the same directory as the `osslsigncode.exe` executable.
To ensure `osslsigncode` can locate and load the CNG engine module (`cng.dll`)
even when it is not installed in the default system engine directory, you can:
Below is an example of how to use osslsigncode with the CNG engine:
- Specify the full or relative path to `cng.dll`:
```
osslsigncode sign \
-engine cng \
-pkcs11cert osslsigncode_cert \
-key osslsigncode_cert \
-engineCtrl store_flags:0 \
-engineCtrl store_name:MY \
-engineCtrl PIN:yourpass \
osslsigncode sign -engine C:\my\engines\cng.dll ...
```
- Or set the `OPENSSL_ENGINES` environment variable to the directory containing
`cng.dll`, and refer to the engine by its ID:
```
set OPENSSL_ENGINES=C:\my\engines
osslsigncode sign -engine cng ...
```
Below is an example of how to use `osslsigncode` with the CNG engine on Windows:
```
set OPENSSL_ENGINES=C:\my\engines
osslsigncode sign ^
-engine cng ^
-pkcs11cert osslsigncode_cert ^
-key osslsigncode_cert ^
-engineCtrl store_flags:0 ^
-engineCtrl store_name:MY ^
-engineCtrl PIN:yourpass ^
-in yourapp.exe -out yourapp-signed.exe
```
+53 -6
View File
@@ -1503,6 +1503,7 @@ static int zipAppendSignatureFile(BIO *bio, ZIP_FILE *zip, uint8_t *data, uint64
if (!get_current_position(bio, &offset)) {
fprintf(stderr, "Unable to get offset\n");
OPENSSL_free(header.fileName);
header.fileName = NULL;
OPENSSL_free(dataToWrite);
return 0; /* FAILED */
}
@@ -1513,6 +1514,7 @@ static int zipAppendSignatureFile(BIO *bio, ZIP_FILE *zip, uint8_t *data, uint64
if (!BIO_write_ex(bio, dataToWrite + written, toWrite, &check)
|| check != toWrite) {
OPENSSL_free(header.fileName);
header.fileName = NULL;
OPENSSL_free(dataToWrite);
return 0; /* FAILED */
}
@@ -1685,6 +1687,8 @@ static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO
out:
OPENSSL_free(header.fileName);
OPENSSL_free(header.extraField);
header.fileName = NULL;
header.extraField = NULL;
return ret;
}
@@ -1852,6 +1856,11 @@ static size_t zipReadFileData(ZIP_FILE *zip, uint8_t **pData, ZIP_CENTRAL_DIRECT
}
if (entry->overrideData) {
compressedSize = entry->overrideData->compressedSize;
/* Validate sizes for safe allocation */
if (compressedSize > (uint64_t)(SIZE_MAX - 1)) {
fprintf(stderr, "Corrupted compressedSize : %" PRIu64"\n", compressedSize);
return 0; /* FAILED */
}
uncompressedSize = entry->overrideData->uncompressedSize;
compressedData = OPENSSL_zalloc(compressedSize + 1);
memcpy(compressedData, entry->overrideData->data, compressedSize);
@@ -1863,6 +1872,8 @@ static size_t zipReadFileData(ZIP_FILE *zip, uint8_t **pData, ZIP_CENTRAL_DIRECT
if (!zipReadLocalHeader(&header, zip, compressedSize)) {
OPENSSL_free(header.fileName);
OPENSSL_free(header.extraField);
header.fileName = NULL;
header.extraField = NULL;
return 0; /* FAILED */
}
if (header.fileNameLen != entry->fileNameLen
@@ -1873,14 +1884,20 @@ static size_t zipReadFileData(ZIP_FILE *zip, uint8_t **pData, ZIP_CENTRAL_DIRECT
fprintf(stderr, "Local header does not match central directory entry\n");
OPENSSL_free(header.fileName);
OPENSSL_free(header.extraField);
header.fileName = NULL;
header.extraField = NULL;
return 0; /* FAILED */
}
/* we don't really need those */
OPENSSL_free(header.fileName);
OPENSSL_free(header.extraField);
header.fileName = NULL;
header.extraField = NULL;
if (compressedSize > (uint64_t)zip->fileSize - entry->offsetOfLocalHeader) {
fprintf(stderr, "Corrupted compressedSize : 0x%08" PRIX64 "\n", entry->compressedSize);
/* Validate sizes for safe allocation */
if (compressedSize > (uint64_t)(SIZE_MAX - 1)
|| compressedSize > (uint64_t)zip->fileSize - entry->offsetOfLocalHeader) {
fprintf(stderr, "Corrupted compressedSize : %" PRIu64"\n", compressedSize);
return 0; /* FAILED */
}
compressedData = OPENSSL_zalloc(compressedSize + 1);
@@ -1899,11 +1916,24 @@ static size_t zipReadFileData(ZIP_FILE *zip, uint8_t **pData, ZIP_CENTRAL_DIRECT
*pData = compressedData;
dataSize = compressedSize;
} else if (entry->compression == COMPRESSION_DEFLATE) {
uint8_t *uncompressedData = OPENSSL_zalloc(uncompressedSize + 1);
uint64_t destLen = uncompressedSize;
uint64_t sourceLen = compressedSize;
uint8_t *uncompressedData;
uint64_t destLen, sourceLen;
int ret;
/* Validate sizes for safe allocation */
if (uncompressedSize > (uint64_t)(SIZE_MAX - 1)) {
fprintf(stderr, "Corrupted uncompressedSize : %" PRIu64"\n", uncompressedSize);
return 0; /* FAILED */
}
/* Detect suspicious compression ratio (zip bomb protection) */
if (uncompressedSize > 1024 * 1024 && uncompressedSize / 100 >= compressedSize) {
fprintf(stderr, "Error: suspicious compression ratio\n");
return 0; /* FAILED */
}
uncompressedData = OPENSSL_zalloc(uncompressedSize + 1);
destLen = uncompressedSize;
sourceLen = compressedSize;
ret = zipInflate(uncompressedData, &destLen, compressedData, (uLong *)&sourceLen);
OPENSSL_free(compressedData);
@@ -1970,6 +2000,8 @@ static int zipReadLocalHeader(ZIP_LOCAL_HEADER *header, ZIP_FILE *zip, uint64_t
header->extraFieldLen = fileGetU16(file);
/* file name (variable size) */
if (header->fileNameLen > 0) {
/* fileNameLen is uint16_t (ZIP spec, 2-byte field),
* so fileNameLen + 1 cannot overflow size_t */
header->fileName = OPENSSL_zalloc(header->fileNameLen + 1);
size = fread(header->fileName, 1, header->fileNameLen, file);
if (size != header->fileNameLen) {
@@ -1981,6 +2013,8 @@ static int zipReadLocalHeader(ZIP_LOCAL_HEADER *header, ZIP_FILE *zip, uint64_t
}
/* extra field (variable size) */
if (header->extraFieldLen > 0) {
/* extraFieldLen is uint16_t (ZIP spec, 2-byte field),
* so extraFieldLen + 1 cannot overflow size_t */
header->extraField = OPENSSL_zalloc(header->extraFieldLen + 1);
size = fread(header->extraField, 1, header->extraFieldLen, file);
if (size != header->extraFieldLen) {
@@ -2011,6 +2045,8 @@ static int zipReadLocalHeader(ZIP_LOCAL_HEADER *header, ZIP_FILE *zip, uint64_t
fprintf(stderr, "The input file is not a valid zip file - flags indicate data descriptor, but data descriptor signature does not match\n");
OPENSSL_free(header->fileName);
OPENSSL_free(header->extraField);
header->fileName = NULL;
header->extraField = NULL;
return 0; /* FAILED */
}
header->crc32 = fileGetU32(file);
@@ -2477,6 +2513,8 @@ static ZIP_CENTRAL_DIRECTORY_ENTRY *zipReadNextCentralDirectoryEntry(FILE *file)
entry->offsetOfLocalHeader = fileGetU32(file);
/* file name (variable size) */
if (entry->fileNameLen > 0) {
/* fileNameLen is uint16_t (ZIP spec, 2-byte field),
* so fileNameLen + 1 cannot overflow size_t */
entry->fileName = OPENSSL_zalloc(entry->fileNameLen + 1);
size = fread(entry->fileName, 1, entry->fileNameLen, file);
if (size != entry->fileNameLen) {
@@ -2487,6 +2525,8 @@ static ZIP_CENTRAL_DIRECTORY_ENTRY *zipReadNextCentralDirectoryEntry(FILE *file)
}
/* extra field (variable size) */
if (entry->extraFieldLen > 0) {
/* extraFieldLen is uint16_t (ZIP spec, 2-byte field),
* so extraFieldLen + 1 cannot overflow size_t */
entry->extraField = OPENSSL_zalloc(entry->extraFieldLen + 1);
size = fread(entry->extraField, 1, entry->extraFieldLen, file);
if (size != entry->extraFieldLen) {
@@ -2497,6 +2537,8 @@ static ZIP_CENTRAL_DIRECTORY_ENTRY *zipReadNextCentralDirectoryEntry(FILE *file)
}
/* file comment (variable size) */
if (entry->fileCommentLen > 0) {
/* fileCommentLen is uint16_t (ZIP spec, 2-byte field),
* so fileCommentLen + 1 cannot overflow size_t */
entry->fileComment = OPENSSL_zalloc(entry->fileCommentLen + 1);
size = fread(entry->fileComment, 1, entry->fileCommentLen, file);
if (size != entry->fileCommentLen) {
@@ -2635,6 +2677,8 @@ static int readZipEOCDR(ZIP_EOCDR *eocdr, FILE *file)
}
#endif
if (eocdr->commentLen > 0) {
/* ZIP_EOCDR commentLen is uint16_t (ZIP spec, 2-byte field),
* so fileCommentLen + 1 cannot overflow size_t */
eocdr->comment = OPENSSL_zalloc(eocdr->commentLen + 1);
size = fread(eocdr->comment, 1, eocdr->commentLen, file);
if (size != eocdr->commentLen) {
@@ -2744,7 +2788,10 @@ static int get_current_position(BIO *bio, uint64_t *offset)
FILE *file = NULL;
int64_t pos;
BIO_get_fp(bio, &file);
if (BIO_get_fp(bio, &file) != 1 || file == NULL) {
fprintf(stderr, "BIO_get_fp() failed\n");
return 0; /* FAILED */
}
pos = ftello(file);
if (pos < 0) {
return 0; /* FAILED */
+4 -3
View File
@@ -342,9 +342,10 @@ static int cab_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
const u_char *p = content_val->data;
SpcIndirectDataContent *idc = d2i_SpcIndirectDataContent(NULL, &p, content_val->length);
if (idc) {
if (idc->messageDigest && idc->messageDigest->digest && idc->messageDigest->digestAlgorithm) {
mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm);
memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)idc->messageDigest->digest->length);
if (spc_indirect_data_content_get_digest(idc, mdbuf, &mdtype) < 0) {
fprintf(stderr, "Failed to extract message digest from signature\n\n");
SpcIndirectDataContent_free(idc);
return 0; /* FAILED */
}
SpcIndirectDataContent_free(idc);
}
+4 -8
View File
@@ -390,16 +390,12 @@ static int cat_print_content_member_digest(ASN1_TYPE *content)
idc = d2i_SpcIndirectDataContent(NULL, &data, ASN1_STRING_length(value));
if (!idc)
return 0; /* FAILED */
if (idc->messageDigest && idc->messageDigest->digest && idc->messageDigest->digestAlgorithm) {
/* get a digest algorithm a message digest of the file from the content */
mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm);
memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)idc->messageDigest->digest->length);
}
SpcIndirectDataContent_free(idc);
if (mdtype == -1) {
fprintf(stderr, "Failed to extract current message digest\n\n");
if (spc_indirect_data_content_get_digest(idc, mdbuf, &mdtype) < 0) {
fprintf(stderr, "Failed to extract message digest from signature\n\n");
SpcIndirectDataContent_free(idc);
return 0; /* FAILED */
}
SpcIndirectDataContent_free(idc);
printf("\tHash algorithm: %s\n", OBJ_nid2sn(mdtype));
print_hash("\tMessage digest", "", mdbuf, EVP_MD_size(EVP_get_digestbynid(mdtype)));
return 1; /* OK */
+4 -9
View File
@@ -96,16 +96,11 @@ function(add_compile_flags target)
message(WARNING "No stack protection supported")
endif(HAVE_STACK_PROTECTOR)
endif(HAVE_STACK_PROTECTOR_ALL)
# Support address space layout randomization (ASLR)
if(NOT (MINGW OR CYGWIN OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang"
OR ((CMAKE_SYSTEM_NAME MATCHES Darwin) AND (CMAKE_C_COMPILER_ID MATCHES Clang))))
# Support address space layout randomization (ASLR) / PIE
if(UNIX AND NOT APPLE)
target_compile_options(${target} PRIVATE -fPIE)
target_link_options(${target} PRIVATE -fPIE -pie)
target_link_options(${target} PRIVATE -Wl,-z,relro)
target_link_options(${target} PRIVATE -Wl,-z,now)
target_link_options(${target} PRIVATE -Wl,-z,noexecstack)
endif(NOT (MINGW OR CYGWIN OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang"
OR ((CMAKE_SYSTEM_NAME MATCHES Darwin) AND (CMAKE_C_COMPILER_ID MATCHES Clang))))
target_link_options(${target} PRIVATE -fPIE -pie -Wl,-z,relro,-z,now,-z,noexecstack)
endif(UNIX AND NOT APPLE)
target_link_options(${target} PRIVATE -fstack-check)
add_compile_flag_to_targets(${target})
endif(MSVC)
+1341 -638
View File
File diff suppressed because it is too large Load Diff
+18 -7
View File
@@ -10,6 +10,7 @@ from csv import reader
from requests import get
from requests.exceptions import RequestException
from concurrent.futures import ThreadPoolExecutor
from re import search
def download_cert(hash):
for attempt in range(10):
@@ -17,23 +18,33 @@ def download_cert(hash):
sleep(10)
try:
creds = f'{attempt}{hash}:{attempt}{hash}'
resp = get(f'https://crt.sh/?d={hash}',
proxies=dict(https=f'socks5://{creds}@127.0.0.1:9050'))
proxies = dict(https=f'socks5://{creds}@127.0.0.1:9050')
url = f'https://crt.sh/?sha1={hash}&match=='
resp = get(url, proxies=proxies)
resp.raise_for_status()
m = search(r'\bid=(\d+)\b', resp.content.decode('ascii', 'replace'))
id = m.group(1)
url = f'https://crt.sh/?d={id}'
resp = get(url, proxies=proxies)
resp.raise_for_status()
print('.', file=stderr, end='')
stderr.flush()
return resp.content.decode('utf-8')
except RequestException as e:
print(f'\nAttempt {attempt}: {e}', file=stderr)
return resp.content.decode('utf-8', 'replace')
except Exception as e:
print(f'\n{url} attempt {attempt}: {e}', file=stderr)
print('\nGiving up on', hash, file=stderr)
resp = get('https://ccadb-public.secure.force.com/microsoft/IncludedCACertificateReportForMSFTCSV')
resp = get('https://ccadb.my.salesforce-sites.com/microsoft/IncludedCACertificateReportForMSFTCSV')
resp.raise_for_status()
lines = resp.content.decode('utf-8').splitlines()[1:]
hashes = [row[4] for row in reader(lines)
if row[0] != 'Disabled'
or row[4] == 'F38406E540D7A9D90CB4A9479299640FFB6DF9E224ECC7A01C0D9558D8DAD77D']
with ThreadPoolExecutor(max_workers=20) as executor:
with ThreadPoolExecutor(max_workers=10) as executor:
certs = executor.map(download_cert, hashes)
for cert in certs:
if cert is not None:
+68
View File
@@ -17,6 +17,7 @@ static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX
static int pkcs7_signer_info_add_sequence_number(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
static STACK_OF(X509) *X509_chain_get_sorted(FILE_FORMAT_CTX *ctx, int signer);
static int X509_compare(const X509 *const *a, const X509 *const *b);
static void sk_X509_remove_duplicates(STACK_OF(X509) *chain);
/*
* Common functions
@@ -562,6 +563,37 @@ int compare_digests(u_char *mdbuf, u_char *cmdbuf, int mdtype)
return mdok;
}
/*
* Safely extract digest from SpcIndirectDataContent with bounds checking.
* This function validates that the digest length from the ASN.1 structure
* does not exceed the destination buffer size, preventing buffer overflows
* from maliciously crafted signatures.
* [in] idc: parsed SpcIndirectDataContent structure
* [out] mdbuf: output buffer (must be at least EVP_MAX_MD_SIZE bytes)
* [out] mdtype: digest algorithm NID
* [returns] digest length on success, -1 on error
*/
int spc_indirect_data_content_get_digest(SpcIndirectDataContent *idc, u_char *mdbuf, int *mdtype)
{
int digest_len;
if (!idc || !idc->messageDigest || !idc->messageDigest->digest ||
!idc->messageDigest->digestAlgorithm) {
return -1; /* FAILED */
}
digest_len = idc->messageDigest->digest->length;
/* Validate digest length to prevent buffer overflow */
if (digest_len <= 0 || digest_len > EVP_MAX_MD_SIZE) {
fprintf(stderr, "Invalid digest length in signature: %d (expected 1-%d)\n",
digest_len, EVP_MAX_MD_SIZE);
return -1; /* FAILED */
}
*mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm);
memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)digest_len);
return digest_len; /* OK */
}
/*
* Helper functions
*/
@@ -617,6 +649,10 @@ static int spc_indirect_data_content_create(u_char **blob, int *len, FILE_FORMAT
idc->data->value->type = V_ASN1_SEQUENCE;
idc->data->value->value.sequence = ASN1_STRING_new();
idc->data->type = ctx->format->data_blob_get(&p, &l, ctx);
if (!idc->data->type) {
SpcIndirectDataContent_free(idc);
return 0; /* FAILED */
}
idc->data->value->value.sequence->data = p;
idc->data->value->value.sequence->length = l;
idc->messageDigest->digestAlgorithm->algorithm = OBJ_nid2obj(mdtype);
@@ -763,6 +799,9 @@ static STACK_OF(X509) *X509_chain_get_sorted(FILE_FORMAT_CTX *ctx, int signer)
}
/* sort certificate chain using the supplied comparison function */
sk_X509_sort(chain);
/* remove duplicates */
sk_X509_remove_duplicates(chain);
return chain;
}
@@ -814,6 +853,35 @@ static int X509_compare(const X509 *const *a, const X509 *const *b)
return ret;
}
/*
* Remove duplicate certificates from a sorted STACK_OF(X509).
*
* This function assumes the stack is sorted according to X.690-compliant
* certificate comparison, so duplicate certificates appear consecutively.
* It iterates through the stack and removes any duplicate certificates
* by comparing each element with its immediate predecessor.
* The stack is modified in place.
*/
static void sk_X509_remove_duplicates(STACK_OF(X509) *chain)
{
int i, n = sk_X509_num(chain);
if (n < 2)
return;
/* start from the second element */
for (i = 1; i < n; ) {
if (!X509_cmp(sk_X509_value(chain, i - 1), sk_X509_value(chain, i))) {
/* duplicate found: remove the certificate at index i */
(void)sk_X509_delete(chain, i);
n--; /* reduce stack size since one element was removed */
/* do not increment i, as next element shifts into index i */
} else {
i++; /* advance only if no removal was done */
}
}
}
/*
Local Variables:
c-basic-offset: 4
+1
View File
@@ -25,6 +25,7 @@ MsCtlContent *ms_ctl_content_get(PKCS7 *p7);
ASN1_TYPE *catalog_content_get(CatalogAuthAttr *attribute);
SpcLink *spc_link_obsolete_get(void);
int compare_digests(u_char *mdbuf, u_char *cmdbuf, int mdtype);
int spc_indirect_data_content_get_digest(SpcIndirectDataContent *idc, u_char *mdbuf, int *mdtype);
/*
Local Variables:
+4 -3
View File
@@ -419,9 +419,10 @@ static int msi_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
const u_char *p = content_val->data;
SpcIndirectDataContent *idc = d2i_SpcIndirectDataContent(NULL, &p, content_val->length);
if (idc) {
if (idc->messageDigest && idc->messageDigest->digest && idc->messageDigest->digestAlgorithm) {
mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm);
memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)idc->messageDigest->digest->length);
if (spc_indirect_data_content_get_digest(idc, mdbuf, &mdtype) < 0) {
fprintf(stderr, "Failed to extract message digest from signature\n\n");
SpcIndirectDataContent_free(idc);
return 0; /* FAILED */
}
SpcIndirectDataContent_free(idc);
}
+133 -114
View File
@@ -244,6 +244,7 @@ static PKCS7 *pkcs7_get_sigfile(FILE_FORMAT_CTX *ctx);
static void print_cert(X509 *cert, int i);
static int x509_store_load_crlfile(X509_STORE *store, char *cafile, char *crlfile);
static void load_objects_from_store(const char *url, char *pass, EVP_PKEY **pkey, STACK_OF(X509) *certs, STACK_OF(X509_CRL) *crls);
static BIO *bio_new_file(const char *filename, const char *mode);
#ifndef OPENSSL_NO_ENGINE
static void engine_control_set(GLOBAL_OPTIONS *options, const char *arg);
#endif /* OPENSSL_NO_ENGINE */
@@ -797,63 +798,37 @@ static int verify_callback(int ok, X509_STORE_CTX *ctx)
/*
* Read data from socket BIO
* [in] s_bio: socket BIO
* [in] rctx: open connection context
* [in] use_ssl: HTTPS request switch
* [returns] memory BIO
*/
static BIO *socket_bio_read(BIO *s_bio, OSSL_HTTP_REQ_CTX *rctx, int use_ssl)
static BIO *socket_bio_read(BIO *s_bio)
{
int retry = 1, ok = 0, written = 0, resp_len = 0;
int retry = 1, ok = 0;
char *buf = OPENSSL_malloc(OSSL_HTTP_DEFAULT_MAX_RESP_LEN);
BIO *resp = BIO_new(BIO_s_mem());
if (rctx) {
resp_len = (int)OSSL_HTTP_REQ_CTX_get_resp_len(rctx);
}
if (resp_len == 0) {
if (use_ssl)
BIO_ssl_shutdown(s_bio);
else {
int fd = (int)BIO_get_fd(s_bio, NULL);
if (fd >= 0) {
#ifdef WIN32
(void)shutdown(fd, SD_SEND);
#else /* WIN32 */
(void)shutdown(fd, SHUT_WR);
#endif /* WIN32 */
}
}
}
ERR_clear_error();
while (retry) {
int n;
errno = 0;
n = BIO_read(s_bio, buf, OSSL_HTTP_DEFAULT_MAX_RESP_LEN);
if (n > 0) {
written += BIO_write(resp, buf, n);
(void)BIO_write(resp, buf, n);
} else if (BIO_eof(s_bio) == 1) {
ok = 1;
retry = 0; /* EOF */
retry = 0; /* HTTP EOF */
} else if (BIO_should_retry(s_bio)) {
} else {
unsigned long err = ERR_get_error();
if (err == 0) {
ok = 1;
retry = 0; /* use_ssl EOF */
retry = 0; /* HTTPS EOF */
} else {
fprintf(stderr, "\nHTTP failure: error %ld: %s\n", err, ERR_reason_error_string(err));
retry = 0; /* FAILED */
}
}
if (resp_len > 0 && resp_len == written) {
ok = 1;
retry = 0; /* all response has been read */
}
}
OSSL_HTTP_close(rctx, ok);
OPENSSL_free(buf);
if (!ok) {
BIO_free_all(resp);
@@ -915,12 +890,10 @@ static void check_authenticode_timestamp(BIO **resp)
static BIO *bio_get_http(char *url, BIO *req, char *proxy, int rfc3161, char *cafile, char *crlfile)
{
BIO *tmp_bio = NULL, *s_bio = NULL, *resp = NULL;
OSSL_HTTP_REQ_CTX *rctx = NULL;
HTTP_TLS_Info info;
SSL_CTX *ssl_ctx = NULL;
char *server = NULL, *port = NULL, *path = NULL;
int timeout = -1; /* blocking mode, exactly one try, see BIO_do_connect_retry() */
int keep_alive = 1; /* prefer */
int use_ssl = 0;
if (!url) {
@@ -956,10 +929,16 @@ static BIO *bio_get_http(char *url, BIO *req, char *proxy, int rfc3161, char *ca
info.ssl_ctx = ssl_ctx;
if (!req) { /* GET */
const char *expected_content_type = "application/pkix-crl";
/*
* HTTP server implementations accessed via the URI SHOULD specify the
* media type application/pkix-crl in the Content-Type header field of
* the response (RFC 5280, section 4.2.1.13).
* In practice, some CRL distribution points return "application/octet-stream"
* instead. Therefore, do not enforce the Content-Type and rely on the CRL
* parser to validate the response content.
*/
s_bio = OSSL_HTTP_get(url, proxy, NULL, NULL, NULL, http_tls_cb, &info, 0,
NULL, expected_content_type, 0, 0, timeout);
NULL, NULL, 0, 0, timeout);
} else { /* POST */
const char *content_type = "application/timestamp-query"; /* RFC3161 Timestamp */
const char *expected_content_type = "application/timestamp-reply";
@@ -974,9 +953,9 @@ static BIO *bio_get_http(char *url, BIO *req, char *proxy, int rfc3161, char *ca
content_type = "application/octet-stream"; /* Authenticode Timestamp */
expected_content_type = "application/octet-stream";
}
s_bio = OSSL_HTTP_transfer(&rctx, server, port, path, use_ssl, proxy, NULL,
s_bio = OSSL_HTTP_transfer(NULL, server, port, path, use_ssl, proxy, NULL,
NULL, NULL, http_tls_cb, &info, 0, NULL, content_type, req,
expected_content_type, 0, 0, timeout, keep_alive);
expected_content_type, 0, 0, timeout, 0);
BIO_free(tmp_bio);
}
OPENSSL_free(server);
@@ -985,7 +964,7 @@ static BIO *bio_get_http(char *url, BIO *req, char *proxy, int rfc3161, char *ca
SSL_CTX_free(ssl_ctx);
if (s_bio) {
resp = socket_bio_read(s_bio, rctx, use_ssl);
resp = socket_bio_read(s_bio);
BIO_free_all(s_bio);
if (resp && req && !rfc3161)
check_authenticode_timestamp(&resp);
@@ -1277,7 +1256,7 @@ static int add_timestamp_builtin(PKCS7 *p7, FILE_FORMAT_CTX *ctx)
TS_RESP *response = NULL;
int i, res = 1;
btmp = BIO_new_file(ctx->options->tsa_certfile, "rb");
btmp = bio_new_file(ctx->options->tsa_certfile, "rb");
if (!btmp) {
fprintf(stderr, "Failed to read Time-Stamp Authority certificate file: %s\n", ctx->options->tsa_certfile);
return 0; /* FAILED */
@@ -1285,7 +1264,7 @@ static int add_timestamp_builtin(PKCS7 *p7, FILE_FORMAT_CTX *ctx)
/* .pem certificate file */
chain = X509_chain_read_certs(btmp, NULL);
BIO_free(btmp);
btmp = BIO_new_file(ctx->options->tsa_keyfile, "rb");
btmp = bio_new_file(ctx->options->tsa_keyfile, "rb");
if (!btmp) {
fprintf(stderr, "Failed to read private key file: %s\n", ctx->options->tsa_keyfile);
return 0; /* FAILED */
@@ -1766,7 +1745,7 @@ static char *x509_name_to_utf8(const X509_NAME *name)
flags = XN_FLAG_RFC2253 | ASN1_STRFLGS_UTF8_CONVERT |
ASN1_STRFLGS_ESC_CTRL;
flags &= ~ASN1_STRFLGS_ESC_MSB;
flags &= ~(unsigned long)ASN1_STRFLGS_ESC_MSB;
bio = BIO_new(BIO_s_mem());
if (!bio)
@@ -1922,11 +1901,22 @@ static int verify_ca_callback(int ok, X509_STORE_CTX *ctx)
static int verify_crl_callback(int ok, X509_STORE_CTX *ctx)
{
X509_CRL *crl;
int error = X509_STORE_CTX_get_error(ctx);
int depth = X509_STORE_CTX_get_error_depth(ctx);
X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx);
print_cert(current_cert, depth);
crl = X509_STORE_CTX_get0_current_crl(ctx);
if (crl) {
BIO *bio = BIO_new_fp(stdout, BIO_NOCLOSE);
X509_CRL_print(bio, crl);
BIO_free(bio);
printf("\n");
}
if (!ok) {
if (trusted_cert(current_cert, error)) {
return 1;
@@ -2534,9 +2524,14 @@ static int verify_authenticode(FILE_FORMAT_CTX *ctx, PKCS7 *p7, time_t time, X50
if (!crlok)
goto out;
}
/* check extended key usage flag XKU_CODE_SIGN */
/* keyUsage, if present, must permit digitalSignature (RFC 5280 section 4.2.1.3) */
if (!(X509_get_key_usage(signer) & X509v3_KU_DIGITAL_SIGNATURE)) {
fprintf(stderr, "Signer certificate rejected: keyUsage does not permit digitalSignature\n");
goto out;
}
/* extendedKeyUsage, if present, must permit codeSigning (RFC 5280 section 4.2.1.12) */
if (!(X509_get_extended_key_usage(signer) & XKU_CODE_SIGN)) {
fprintf(stderr, "Unsupported Signer's certificate purpose XKU_CODE_SIGN\n");
fprintf(stderr, "Signer certificate rejected: extendedKeyUsage does not permit codeSigning\n");
goto out;
}
@@ -3087,13 +3082,8 @@ static int verify_content_member_digest(FILE_FORMAT_CTX *ctx, ASN1_TYPE *content
fprintf(stderr, "Failed to extract SpcIndirectDataContent data\n");
return 1; /* FAILED */
}
if (idc->messageDigest && idc->messageDigest->digest && idc->messageDigest->digestAlgorithm) {
/* get a digest algorithm a message digest of the file from the content */
mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm);
memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)idc->messageDigest->digest->length);
}
if (mdtype == -1) {
fprintf(stderr, "Failed to extract current message digest\n\n");
if (spc_indirect_data_content_get_digest(idc, mdbuf, &mdtype) < 0) {
fprintf(stderr, "Failed to extract message digest from signature\n\n");
SpcIndirectDataContent_free(idc);
return 1; /* FAILED */
}
@@ -3605,11 +3595,11 @@ static void usage(const char *argv0, const char *cmd)
printf("%1s[ --help ]\n\n", "");
}
if (on_list(cmd, cmds_sign)) {
printf("%1s[ sign ] -pkcs12 <pkcs12file> | ( [ -certs <certfile> | -spc <certfile> ]\n", "");
printf("%1s[ sign ] -pkcs12 <file> | ( [ -certs <file|URI> | -spc <file> ]\n", "");
#if !defined(OPENSSL_NO_ENGINE) || OPENSSL_VERSION_NUMBER>=0x30000000L
printf("%12s( -key <keyfile> | ( -key <pkcs11 key URI> -pkcs11module <module> [ -pkcs11cert <pkcs11 cert URI> ] )\n", "");
printf("%12s( -key <file|URI> [ -pkcs11module <module> ] [ -pkcs11cert <pkcs11 cert URI> ] )\n", "");
#else /* !defined(OPENSSL_NO_ENGINE) || OPENSSL_VERSION_NUMBER>=0x30000000L */
printf("%12s-key <keyfile> )\n", "");
printf("%12s-key <file|URI> )\n", "");
#endif /* !defined(OPENSSL_NO_ENGINE) || OPENSSL_VERSION_NUMBER>=0x30000000L */
#if OPENSSL_VERSION_NUMBER>=0x30000000L
printf("%12s[ -provider <provider> | ", "");
@@ -3619,7 +3609,7 @@ static void usage(const char *argv0, const char *cmd)
#endif /* OPENSSL_NO_ENGINE */
#endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */
#ifndef OPENSSL_NO_ENGINE
printf("%s( -engine <engine> [ -login ] [ -engineCtrl <command[:parameter]> ] ) ] ) )\n", "");
printf("%s( -engine <engine> [ -login ] [ -engineCtrl <command[:parameter]> ] ) ] )\n", "");
#endif /* OPENSSL_NO_ENGINE */
#if OPENSSL_VERSION_NUMBER>=0x30000000L
printf("%12s[ -nolegacy ]\n", "");
@@ -3630,73 +3620,73 @@ static void usage(const char *argv0, const char *cmd)
#endif /* PROVIDE_ASKPASS */
printf("%1s[ -readpass <file> ]\n", "");
printf("%12s(use \"-\" with readpass to read from stdin)\n", "");
printf("%12s[ -ac <crosscertfile> ]\n", "");
printf("%12s[ -ac <file> ]\n", "");
printf("%12s[ -h {md5,sha1,sha2(56),sha384,sha512} ]\n", "");
printf("%12s[ -n <desc> ] [ -i <url> ] [ -jp <level> ] [ -comm ]\n", "");
printf("%12s[ -ph ]\n", "");
printf("%12s[ -t <timestampurl> [ -t ... ] [ -p <proxy> ] [ -noverifypeer ]\n", "");
printf("%12s[ -ts <timestampurl> [ -ts ... ] [ -p <proxy> ] [ -noverifypeer ] ]\n", "");
printf("%12s[ -TSA-certs <TSA-certfile> ] [ -TSA-key <TSA-keyfile> ]\n", "");
printf("%12s[ -TSA-certs <file> ] [ -TSA-key <file> ]\n", "");
printf("%12s[ -TSA-time <unix-time> ]\n", "");
printf("%12s[ -HTTPS-CAfile <infile> ]\n", "");
printf("%12s[ -HTTPS-CRLfile <infile> ]\n", "");
printf("%12s[ -HTTPS-CAfile <file> ]\n", "");
printf("%12s[ -HTTPS-CRLfile <file> ]\n", "");
printf("%12s[ -time <unix-time> ]\n", "");
printf("%12s[ -addUnauthenticatedBlob [ -blobFile <blobfile> ] ]\n", "");
printf("%12s[ -addUnauthenticatedBlob [ -blobFile <file> ] ]\n", "");
printf("%12s[ -nest ]\n", "");
printf("%12s[ -verbose ]\n", "");
printf("%12s[ -add-msi-dse ]\n", "");
printf("%12s[ -pem ]\n", "");
printf("%12s[ -in ] <infile> [-out ] <outfile>\n\n", "");
printf("%12s[ -in ] <file> [-out ] <file>\n\n", "");
}
if (on_list(cmd, cmds_extract_data)) {
printf("%1sextract-data [ -pem ]\n", "");
printf("%12s[ -h {md5,sha1,sha2(56),sha384,sha512} ]\n", "");
printf("%12s[ -ph ]\n", "");
printf("%12s[ -add-msi-dse ]\n", "");
printf("%12s[ -in ] <infile> [ -out ] <datafile>\n\n", "");
printf("%12s[ -in ] <file> [ -out ] <file>\n\n", "");
}
if (on_list(cmd, cmds_add)) {
printf("%1sadd [ -addUnauthenticatedBlob [ -blobFile <blobfile> ] ]\n", "");
printf("%1sadd [ -addUnauthenticatedBlob [ -blobFile <file> ] ]\n", "");
printf("%12s[ -t <timestampurl> [ -t ... ] [ -p <proxy> ] [ -noverifypeer ]\n", "");
printf("%12s[ -ts <timestampurl> [ -ts ... ] [ -p <proxy> ] [ -noverifypeer ] ]\n", "");
printf("%12s[ -TSA-certs <TSA-certfile> ] [ -TSA-key <TSA-keyfile> ]\n", "");
printf("%12s[ -TSA-certs <file> ] [ -TSA-key <file> ]\n", "");
printf("%12s[ -TSA-time <unix-time> ]\n", "");
printf("%12s[ -HTTPS-CAfile <infile> ]\n", "");
printf("%12s[ -HTTPS-CRLfile <infile> ]\n", "");
printf("%12s[ -HTTPS-CAfile <file> ]\n", "");
printf("%12s[ -HTTPS-CRLfile <file> ]\n", "");
printf("%12s[ -h {md5,sha1,sha2(56),sha384,sha512} ]\n", "");
printf("%12s[ -index <index> ]\n", "");
printf("%12s[ -verbose ]\n", "");
printf("%12s[ -add-msi-dse ]\n", "");
printf("%12s[ -in ] <infile> [ -out ] <outfile>\n\n", "");
printf("%12s[ -in ] <file> [ -out ] <file>\n\n", "");
}
if (on_list(cmd, cmds_attach)) {
printf("%1sattach-signature [ -sigin ] <sigfile>\n", "");
printf("%12s[ -CAfile <infile> ]\n", "");
printf("%12s[ -CRLfile <infile> ]\n", "");
printf("%12s[ -TSA-CAfile <infile> ]\n", "");
printf("%12s[ -TSA-CRLfile <infile> ]\n", "");
printf("%1sattach-signature [ -sigin ] <file>\n", "");
printf("%12s[ -CAfile <file> ]\n", "");
printf("%12s[ -CRLfile <file> ]\n", "");
printf("%12s[ -TSA-CAfile <file> ]\n", "");
printf("%12s[ -TSA-CRLfile <file> ]\n", "");
printf("%12s[ -time <unix-time> ]\n", "");
printf("%12s[ -h {md5,sha1,sha2(56),sha384,sha512} ]\n", "");
printf("%12s[ -require-leaf-hash {md5,sha1,sha2(56),sha384,sha512}:XXXXXXXXXXXX... ]\n", "");
printf("%12s[ -nest ]\n", "");
printf("%12s[ -add-msi-dse ]\n", "");
printf("%12s[ -in ] <infile> [ -out ] <outfile>\n\n", "");
printf("%12s[ -in ] <file> [ -out ] <file>\n\n", "");
}
if (on_list(cmd, cmds_extract)) {
printf("%1sextract-signature [ -pem ]\n", "");
printf("%12s[ -in ] <infile> [ -out ] <sigfile>\n\n", "");
printf("%12s[ -in ] <file> [ -out ] <file>\n\n", "");
}
if (on_list(cmd, cmds_remove))
printf("%1sremove-signature [ -in ] <infile> [ -out ] <outfile>\n\n", "");
printf("%1sremove-signature [ -in ] <file> [ -out ] <file>\n\n", "");
if (on_list(cmd, cmds_verify)) {
printf("%1sverify [ -in ] <infile>\n", "");
printf("%12s[ -c | -catalog <infile> ]\n", "");
printf("%12s[ -CAfile <infile> ]\n", "");
printf("%12s[ -CRLfile <infile> ]\n", "");
printf("%12s[ -HTTPS-CAfile <infile> ]\n", "");
printf("%12s[ -HTTPS-CRLfile <infile> ]\n", "");
printf("%12s[ -TSA-CAfile <infile> ]\n", "");
printf("%12s[ -TSA-CRLfile <infile> ]\n", "");
printf("%1sverify [ -in ] <file>\n", "");
printf("%12s[ -c | -catalog <file> ]\n", "");
printf("%12s[ -CAfile <file> ]\n", "");
printf("%12s[ -CRLfile <file> ]\n", "");
printf("%12s[ -HTTPS-CAfile <file> ]\n", "");
printf("%12s[ -HTTPS-CRLfile <file> ]\n", "");
printf("%12s[ -TSA-CAfile <file> ]\n", "");
printf("%12s[ -TSA-CRLfile <file> ]\n", "");
printf("%12s[ -p <proxy> ]\n", "");
printf("%12s[ -index <index> ]\n", "");
printf("%12s[ -ignore-timestamp ]\n", "");
@@ -3857,7 +3847,7 @@ static void help_for(const char *argv0, const char *cmd)
if (on_list(cmd, cmds_CAfile))
printf("%-24s= the file containing one or more trusted certificates in PEM format\n", "-CAfile");
if (on_list(cmd, cmds_certs))
printf("%-24s= the signing certificate to use\n", "-certs, -spc");
printf("%-24s= certificate chain (signing cert + intermediates)\n", "-certs, -spc");
if (on_list(cmd, cmds_comm))
printf("%-24s= set commercial purpose (default: individual purpose)\n", "-comm");
if (on_list(cmd, cmds_CRLfile))
@@ -3882,7 +3872,7 @@ static void help_for(const char *argv0, const char *cmd)
printf("%-24s= disable legacy mode and don't automatically load the legacy provider\n", "-nolegacy");
#endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */
if (on_list(cmd, cmds_key))
printf("%-24s= the private key to use or PKCS#11 URI identifies a key in the token\n", "-key");
printf("%-24s= private key (optionally with signing cert) from file or URI\n", "-key");
if (on_list(cmd, cmds_n))
printf("%-24s= specifies a description of the signed content\n", "-n");
if (on_list(cmd, cmds_nest))
@@ -4104,7 +4094,7 @@ err:
*/
static int read_der_keyfile(GLOBAL_OPTIONS *options)
{
BIO *btmp = BIO_new_file(options->keyfile, "rb");
BIO *btmp = bio_new_file(options->keyfile, "rb");
if (!btmp) {
fprintf(stderr, "Failed to read private key file: %s\n", options->keyfile);
@@ -4130,7 +4120,7 @@ static int read_der_keyfile(GLOBAL_OPTIONS *options)
static int read_pkcs7_certfile(GLOBAL_OPTIONS *options)
{
PKCS7 *p7;
BIO *btmp = BIO_new_file(options->certfile, "rb");
BIO *btmp = bio_new_file(options->certfile, "rb");
if (!btmp) {
fprintf(stderr, "Failed to read certificate from: %s\n",
@@ -4364,8 +4354,8 @@ static int read_crypto_params(GLOBAL_OPTIONS *options)
(void)provider_load(options->provider);
}
#endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */
/* Load the private key ('-key' option) */
load_objects_from_store(options->keyfile, options->pass, &options->pkey, NULL, NULL);
/* Load the private key and the signing certificate ('-key' option) */
load_objects_from_store(options->keyfile, options->pass, &options->pkey, options->certs, NULL);
}
#if OPENSSL_VERSION_NUMBER<0x1010108f
/* Workaround for OpenSSL 1.1.1g and older, where the store API does not
@@ -4609,6 +4599,26 @@ static int file_exists(const char *filename)
return 0; /* File does not exist */
}
static BIO *bio_new_file(const char *filename, const char *mode)
{
FILE *file;
BIO *bio;
if (!filename)
return NULL;
file = fopen(filename, mode);
if (!file)
return NULL;
bio = BIO_new_fp(file, BIO_CLOSE);
if (!bio) {
fclose(file);
return NULL;
}
return bio;
}
/*
* [in] argc, argv
* [in, out] options: structure holds the input data
@@ -5068,7 +5078,7 @@ static void engine_control_set(GLOBAL_OPTIONS *options, const char *arg)
}
#endif /* OPENSSL_NO_ENGINE */
int main(int argc, char **argv)
static int main_execute(int argc, char **argv)
{
FILE_FORMAT_CTX *ctx = NULL;
GLOBAL_OPTIONS options;
@@ -5080,24 +5090,6 @@ int main(int argc, char **argv)
/* reset options */
memset(&options, 0, sizeof(GLOBAL_OPTIONS));
/* Set up OpenSSL */
if (!OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS
| OPENSSL_INIT_ADD_ALL_CIPHERS
| OPENSSL_INIT_ADD_ALL_DIGESTS
| OPENSSL_INIT_LOAD_CONFIG, NULL))
DO_EXIT_0("Failed to init crypto\n");
/* create some MS Authenticode OIDS we need later on */
if (!OBJ_create(SPC_STATEMENT_TYPE_OBJID, NULL, NULL)
/* PKCS9_COUNTER_SIGNATURE exists as OpenSSL OBJ_pkcs9_countersignature */
|| !OBJ_create(MS_JAVA_SOMETHING, NULL, NULL)
|| !OBJ_create(SPC_SP_OPUS_INFO_OBJID, NULL, NULL)
|| !OBJ_create(SPC_NESTED_SIGNATURE_OBJID, NULL, NULL)
|| !OBJ_create(SPC_UNAUTHENTICATED_DATA_BLOB_OBJID, NULL, NULL)
|| !OBJ_create(SPC_RFC3161_OBJID, NULL, NULL)
|| !OBJ_create(PKCS9_SEQUENCE_NUMBER, NULL, NULL))
DO_EXIT_0("Failed to create objects\n");
/* commands and options initialization */
if (!main_configure(argc, argv, &options))
goto err_cleanup;
@@ -5122,14 +5114,12 @@ int main(int argc, char **argv)
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
/* Create outdata file */
outdata = BIO_new_file(options.outfile, "w+bx");
if (!outdata && errno != EEXIST)
outdata = BIO_new_file(options.outfile, "w+b");
/* Create output file — file existence already verified via file_exists() */
outdata = bio_new_file(options.outfile, "w+b");
if (!outdata) {
BIO_free_all(hash);
DO_EXIT_1("Failed to create file: %s\n", options.outfile);
}
}
}
ctx = file_format_script.ctx_new(&options, hash, outdata);
if (!ctx)
@@ -5347,6 +5337,35 @@ err_cleanup:
return ret;
}
int main(int argc, char **argv)
{
int ret = -1;
/* one-time OpenSSL initialization */
if (!OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS
| OPENSSL_INIT_ADD_ALL_CIPHERS
| OPENSSL_INIT_ADD_ALL_DIGESTS
| OPENSSL_INIT_LOAD_CONFIG, NULL))
DO_EXIT_0("Failed to init crypto\n");
/* create some MS Authenticode OIDS we need later on */
if (!OBJ_create(SPC_STATEMENT_TYPE_OBJID, NULL, NULL)
/* PKCS9_COUNTER_SIGNATURE exists as OpenSSL OBJ_pkcs9_countersignature */
|| !OBJ_create(MS_JAVA_SOMETHING, NULL, NULL)
|| !OBJ_create(SPC_SP_OPUS_INFO_OBJID, NULL, NULL)
|| !OBJ_create(SPC_NESTED_SIGNATURE_OBJID, NULL, NULL)
|| !OBJ_create(SPC_UNAUTHENTICATED_DATA_BLOB_OBJID, NULL, NULL)
|| !OBJ_create(SPC_RFC3161_OBJID, NULL, NULL)
|| !OBJ_create(PKCS9_SEQUENCE_NUMBER, NULL, NULL))
DO_EXIT_0("Failed to create objects\n");
/* perform the requested operation */
ret = main_execute(argc, argv);
err_cleanup:
return ret;
}
/*
Local Variables:
c-basic-offset: 4
+204 -42
View File
@@ -163,8 +163,10 @@ static ASN1_OBJECT *pe_spc_image_data_get(u_char **p, int *plen, FILE_FORMAT_CTX
if (EVP_MD_size(ctx->options->md) > EVP_MD_size(EVP_sha1()))
phtype = NID_sha256;
link = pe_page_hash_link_get(ctx, phtype);
if (!link)
if (!link) {
SpcPeImageData_free(pid);
return NULL; /* FAILED */
}
pid->file = link;
} else {
pid->file = spc_link_obsolete_get();
@@ -255,9 +257,11 @@ static int pe_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
SpcIndirectDataContent_free(idc);
return 0; /* FAILED */
}
if (idc->messageDigest && idc->messageDigest->digest && idc->messageDigest->digestAlgorithm) {
mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm);
memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)idc->messageDigest->digest->length);
if (spc_indirect_data_content_get_digest(idc, mdbuf, &mdtype) < 0) {
fprintf(stderr, "Failed to extract message digest from signature\n\n");
OPENSSL_free(ph);
SpcIndirectDataContent_free(idc);
return 0; /* FAILED */
}
SpcIndirectDataContent_free(idc);
}
@@ -402,6 +406,7 @@ static PKCS7 *pe_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
content = spc_indirect_data_content_get(hash, ctx);
if (!content) {
fprintf(stderr, "Failed to get spcIndirectDataContent\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
if (!sign_spc_indirect_data_content(p7, content)) {
@@ -914,12 +919,25 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
uint16_t nsections, opthdr_size;
uint32_t alignment, pagesize, hdrsize;
uint32_t rs, ro, l, lastpos = 0;
int pphlen, phlen, i, pi = 1;
size_t written;
u_char *res, *zeroes;
int mdlen, pphlen, phlen, i, pi = 1;
size_t written, off, sect_off, sect_tbl, need;
u_char *res = NULL, *zeroes = NULL;
char *sections;
const EVP_MD *md = EVP_get_digestbynid(phtype);
BIO *bhash;
BIO *bhash = NULL;
uint32_t filebound;
size_t pphlen_sz, sections_factor;
if (rphlen == NULL || ctx == NULL || ctx->options == NULL || ctx->pe_ctx == NULL
|| ctx->options->indata == NULL)
return NULL;
if (md == NULL)
return NULL;
mdlen = EVP_MD_size(md);
if (mdlen <= 0)
return NULL;
/* NumberOfSections indicates the size of the section table,
* which immediately follows the headers, can be up to 65535 under Vista and later */
@@ -961,10 +979,46 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
fprintf(stderr, "Corrupted optional header size: 0x%08X\n", opthdr_size);
return NULL; /* FAILED */
}
pphlen = 4 + EVP_MD_size(md);
phlen = pphlen * (3 + (int)nsections + (int)(ctx->pe_ctx->fileend / pagesize));
/* Validate that pagesize >= hdrsize to prevent integer underflow */
if (pagesize < hdrsize) {
fprintf(stderr, "Page size (0x%08X) is smaller than header size (0x%08X)\n",
pagesize, hdrsize);
return NULL; /* FAILED */
}
pphlen = 4 + mdlen;
/* Compute an upper bound for result size and guard overflow */
pphlen_sz = (size_t)pphlen;
sections_factor = 3 + (size_t)nsections + ((size_t)ctx->pe_ctx->fileend / pagesize);
if (sections_factor > SIZE_MAX / pphlen_sz) {
fprintf(stderr, "Page hash allocation size would overflow\n");
return NULL; /* FAILED */
}
phlen = (int)(pphlen_sz * sections_factor);
/* Sanity limit - page hash shouldn't exceed reasonable size (16 MB) */
if (phlen < 0 || (size_t)phlen > SIZE_16M) {
fprintf(stderr, "Page hash size exceeds limit: %d\n", phlen);
return NULL; /* FAILED */
}
/* Determine the file boundary for section data validation */
filebound = ctx->pe_ctx->sigpos ? ctx->pe_ctx->sigpos : ctx->pe_ctx->fileend;
/* Validate section table bounds before reading section headers */
sect_off = (size_t)ctx->pe_ctx->header_size + 24u + (size_t)opthdr_size;
sect_tbl = (size_t)nsections * 40u;
if (sect_off > (size_t)filebound || sect_tbl > (size_t)filebound - sect_off) {
fprintf(stderr, "Section table out of bounds: off=%zu size=%zu filebound=%u\n",
sect_off, sect_tbl, filebound);
return NULL; /* FAILED */
}
sections = (char *)ctx->options->indata + sect_off;
bhash = BIO_new(BIO_f_md());
if (bhash == NULL)
return NULL;
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
@@ -977,7 +1031,10 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
BIO_push(bhash, BIO_new(BIO_s_null()));
if (BIO_push(bhash, BIO_new(BIO_s_null())) == NULL) {
BIO_free_all(bhash);
return NULL;
}
if (!BIO_write_ex(bhash, ctx->options->indata, ctx->pe_ctx->header_size + 88, &written)
|| written != ctx->pe_ctx->header_size + 88) {
BIO_free_all(bhash);
@@ -989,36 +1046,84 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
BIO_free_all(bhash);
return NULL; /* FAILED */
}
if (!BIO_write_ex(bhash,
ctx->options->indata + ctx->pe_ctx->header_size + 160 + ctx->pe_ctx->pe32plus*16,
hdrsize - (ctx->pe_ctx->header_size + 160 + ctx->pe_ctx->pe32plus*16), &written)
|| written != hdrsize - (ctx->pe_ctx->header_size + 160 + ctx->pe_ctx->pe32plus*16)) {
off = ctx->pe_ctx->header_size + 160 + (size_t)ctx->pe_ctx->pe32plus * 16;
if (hdrsize < off || hdrsize > filebound) {
BIO_free_all(bhash);
return NULL; /* FAILED: header too small */
}
if (!BIO_write_ex(bhash, ctx->options->indata + off, (size_t)hdrsize - off, &written)
|| written != hdrsize - off) {
BIO_free_all(bhash);
return NULL; /* FAILED */
}
if (pagesize < hdrsize) {
BIO_free_all(bhash);
return NULL; /* FAILED: header larger than page */
}
zeroes = OPENSSL_zalloc((size_t)pagesize);
if (!BIO_write_ex(bhash, zeroes, pagesize - hdrsize, &written)
|| written != pagesize - hdrsize) {
if (zeroes == NULL) {
BIO_free_all(bhash);
return NULL; /* FAILED */
}
if (!BIO_write_ex(bhash, zeroes, (size_t)pagesize - (size_t)hdrsize, &written)
|| written != (size_t)pagesize - (size_t)hdrsize) {
BIO_free_all(bhash);
OPENSSL_free(zeroes);
return NULL; /* FAILED */
}
res = OPENSSL_malloc((size_t)phlen);
if (res == NULL) {
BIO_free_all(bhash);
OPENSSL_free(zeroes);
return NULL; /* FAILED */
}
memset(res, 0, 4);
BIO_gets(bhash, (char*)res + 4, EVP_MD_size(md));
if (BIO_gets(bhash, (char *)res + 4, mdlen) != mdlen) {
BIO_free_all(bhash);
OPENSSL_free(zeroes);
OPENSSL_free(res);
return NULL; /* FAILED */
}
BIO_free_all(bhash);
sections = ctx->options->indata + ctx->pe_ctx->header_size + 24 + opthdr_size;
for (i=0; i<nsections; i++) {
/* Resource Table address and size */
bhash = NULL;
for (i = 0; i < (int)nsections; i++) {
/* SizeOfRawData and PointerToRawData from section header */
rs = GET_UINT32_LE(sections + 16);
ro = GET_UINT32_LE(sections + 20);
if (rs == 0 || rs >= UINT32_MAX) {
if (rs == 0) {
sections += 40;
continue;
}
for (l=0; l<rs; l+=pagesize, pi++) {
PUT_UINT32_LE(ro + l, res + pi*pphlen);
/* Validate section bounds against file size to prevent OOB read */
if (ro >= filebound || rs > filebound - ro) {
fprintf(stderr, "Section %d has invalid bounds: offset=0x%08X, size=0x%08X, fileend=0x%08X\n",
i, ro, rs, filebound);
OPENSSL_free(zeroes);
OPENSSL_free(res);
return NULL; /* FAILED */
}
for (l = 0; l < rs; l += pagesize, pi++) {
need = (size_t)(pi + 1) * (size_t)pphlen;
/* Prevent OOB write into res if pi grows beyond allocated factor */
if (need > (size_t)phlen) {
fprintf(stderr, "Page hash buffer overflow prevented: pi=%d need=%zu phlen=%d\n",
pi, need, phlen);
OPENSSL_free(zeroes);
OPENSSL_free(res);
return NULL; /* FAILED */
}
PUT_UINT32_LE(ro + l, res + (size_t)pi * (size_t)pphlen);
bhash = BIO_new(BIO_f_md());
if (bhash == NULL) {
OPENSSL_free(zeroes);
OPENSSL_free(res);
return NULL;
}
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
@@ -1033,17 +1138,24 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
BIO_push(bhash, BIO_new(BIO_s_null()));
if (rs - l < pagesize) {
if (!BIO_write_ex(bhash, ctx->options->indata + ro + l, rs - l, &written)
|| written != rs - l) {
if (BIO_push(bhash, BIO_new(BIO_s_null())) == NULL) {
BIO_free_all(bhash);
OPENSSL_free(zeroes);
OPENSSL_free(res);
return NULL;
}
if (l < rs && rs - l < pagesize) {
size_t tail = (size_t)(rs - l);
if (!BIO_write_ex(bhash, ctx->options->indata + ro + l, tail, &written)
|| written != tail) {
BIO_free_all(bhash);
OPENSSL_free(zeroes);
OPENSSL_free(res);
return NULL; /* FAILED */
}
if (!BIO_write_ex(bhash, zeroes, pagesize - (rs - l), &written)
|| written != pagesize - (rs - l)) {
if (!BIO_write_ex(bhash, zeroes, pagesize - tail, &written)
|| written != pagesize - tail) {
BIO_free_all(bhash);
OPENSSL_free(zeroes);
OPENSSL_free(res);
@@ -1058,17 +1170,35 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
return NULL; /* FAILED */
}
}
BIO_gets(bhash, (char*)res + pi*pphlen + 4, EVP_MD_size(md));
if (BIO_gets(bhash, (char *)res + (size_t)pi * (size_t)pphlen + 4, mdlen) != mdlen) {
BIO_free_all(bhash);
OPENSSL_free(zeroes);
OPENSSL_free(res);
return NULL; /* FAILED */
}
BIO_free_all(bhash);
bhash = NULL;
}
lastpos = ro + rs;
sections += 40;
}
PUT_UINT32_LE(lastpos, res + pi*pphlen);
memset(res + pi*pphlen + 4, 0, (size_t)EVP_MD_size(md));
/* Final entry */
need = (size_t)(pi + 1) * (size_t)pphlen;
if (need > (size_t)phlen) {
fprintf(stderr, "Page hash buffer overflow prevented at final entry: pi=%d need=%zu phlen=%d\n",
pi, need, phlen);
OPENSSL_free(zeroes);
OPENSSL_free(res);
return NULL; /* FAILED */
}
PUT_UINT32_LE(lastpos, res + (size_t)pi * (size_t)pphlen);
memset(res + (size_t)pi * (size_t)pphlen + 4, 0, (size_t)mdlen);
pi++;
OPENSSL_free(zeroes);
*rphlen = pi*pphlen;
*rphlen = pi * pphlen;
return res;
}
@@ -1088,6 +1218,10 @@ static int pe_verify_page_hash(FILE_FORMAT_CTX *ctx, u_char *ph, int phlen, int
if (!ph)
return 1; /* OK */
cph = pe_page_hash_calc(&cphlen, ctx, phtype);
if (!cph) {
fprintf(stderr, "Page hash verification failed: could not calculate page hash\n");
return 0; /* FAILED */
}
mdok = (phlen == cphlen) && !memcmp(ph, cph, (size_t)phlen);
printf("Page hash algorithm : %s\n", OBJ_nid2sn(phtype));
if (ctx->options->verbose) {
@@ -1190,7 +1324,8 @@ static int pe_check_file(FILE_FORMAT_CTX *ctx)
{
uint32_t real_pe_checksum, sum = 0;
if (!ctx) {
if (ctx == NULL || ctx->pe_ctx == NULL || ctx->options == NULL
|| ctx->options->indata == NULL) {
fprintf(stderr, "Init error\n");
return 0; /* FAILED */
}
@@ -1202,25 +1337,52 @@ static int pe_check_file(FILE_FORMAT_CTX *ctx)
printf("Calculated PE checksum: %08X\n", real_pe_checksum);
printf("Warning: invalid PE checksum\n");
}
/* Signature directory bounds */
if (ctx->pe_ctx->sigpos == 0 || ctx->pe_ctx->siglen == 0
|| ctx->pe_ctx->sigpos > ctx->pe_ctx->fileend) {
|| ctx->pe_ctx->sigpos > ctx->pe_ctx->fileend
|| ctx->pe_ctx->siglen > ctx->pe_ctx->fileend - ctx->pe_ctx->sigpos) {
fprintf(stderr, "No signature found\n");
return 0; /* FAILED */
}
/*
* Validate WIN_CERTIFICATE chain.
* If the sum of the rounded dwLength values does not equal the Size value,
* then either the attribute certificate table or the Size field is corrupted.
*/
while (sum < ctx->pe_ctx->siglen) {
uint32_t len = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->sigpos + sum);
if (ctx->pe_ctx->siglen - len > 8) {
uint32_t len, off;
/* Prevent overflow in sigpos + sum */
if (sum > UINT32_MAX - ctx->pe_ctx->sigpos) {
fprintf(stderr, "Corrupted attribute certificate table\n");
fprintf(stderr, "Attribute certificate table size : %08X\n", ctx->pe_ctx->siglen);
fprintf(stderr, "Attribute certificate entry length: %08X\n\n", len);
return 0; /* FAILED */
}
/* quadword align data */
len += len % 8 ? 8 - len % 8 : 0;
off = ctx->pe_ctx->sigpos + sum;
/* Need at least 4 bytes to read dwLength */
if (off > ctx->pe_ctx->fileend || ctx->pe_ctx->fileend - off < 4) {
fprintf(stderr, "Corrupted attribute certificate table\n");
return 0; /* FAILED */
}
len = GET_UINT32_LE(ctx->options->indata + off);
/* dwLength must include the 8-byte WIN_CERTIFICATE header */
if (len < 8 || len > ctx->pe_ctx->siglen - sum || len > ctx->pe_ctx->fileend - off) {
fprintf(stderr, "Corrupted attribute certificate table\n");
return 0; /* FAILED */
}
/* Quadword align data */
if (len % 8) {
uint32_t pad = 8 - (len % 8);
/* Ensure quadword alignment does not overflow or exceed remaining table size */
if (pad > ctx->pe_ctx->siglen - sum - len) {
fprintf(stderr, "Corrupted attribute certificate table\n");
return 0; /* FAILED */
}
len += pad;
}
sum += len;
}
if (sum != ctx->pe_ctx->siglen) {
+4 -3
View File
@@ -294,9 +294,10 @@ static int script_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
const u_char *p = content_val->data;
SpcIndirectDataContent *idc = d2i_SpcIndirectDataContent(NULL, &p, content_val->length);
if (idc) {
if (idc->messageDigest && idc->messageDigest->digest && idc->messageDigest->digestAlgorithm) {
mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm);
memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)idc->messageDigest->digest->length);
if (spc_indirect_data_content_get_digest(idc, mdbuf, &mdtype) < 0) {
fprintf(stderr, "Failed to extract message digest from signature\n\n");
SpcIndirectDataContent_free(idc);
return 0; /* FAILED */
}
SpcIndirectDataContent_free(idc);
}
+12
View File
@@ -338,6 +338,17 @@ class LeafCertificate(X509Extensions):
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
self.issuer_cert.extensions.get_extension_for_class(SubjectKeyIdentifier).value
)
key_usage = KeyUsage(
digital_signature=True,
content_commitment=False,
key_encipherment=False,
data_encipherment=False,
key_agreement=False,
key_cert_sign=False,
crl_sign=False,
encipher_only=False,
decipher_only=False
)
extended_key_usage = ExtendedKeyUsage(
[ExtendedKeyUsageOID.CODE_SIGNING]
)
@@ -352,6 +363,7 @@ class LeafCertificate(X509Extensions):
.add_extension(BasicConstraints(ca=False, path_length=None), critical=False)
.add_extension(SubjectKeyIdentifier.from_public_key(public_key), critical=False)
.add_extension(authority_key, critical=False)
.add_extension(key_usage, critical=False)
.add_extension(extended_key_usage, critical=False)
.add_extension(self.create_x509_crldp(), critical=False)
.sign(self.issuer_key, SHA256())