mirror of
https://github.com/mtrojnar/osslsigncode.git
synced 2025-07-03 19:52:47 -05:00
Compare commits
37 Commits
Author | SHA1 | Date | |
---|---|---|---|
73d7cf011e | |||
7affd85c46 | |||
d8a182614c | |||
ac672640be | |||
5d68e8699a | |||
b48458499b | |||
4731667c35 | |||
85594d9fb2 | |||
5f60cc6563 | |||
77b2b30d1f | |||
e0d652b987 | |||
b774a56aa9 | |||
6eaf0d9368 | |||
d471b51db5 | |||
7b12abf21f | |||
f248286d6f | |||
5db237f242 | |||
95c5a4451b | |||
f0207411b9 | |||
aef958f880 | |||
a6d3be739e | |||
4eeeec32b4 | |||
ce196ce147 | |||
289c345280 | |||
bdea1d1c2a | |||
45fedd9e50 | |||
e177ded9a5 | |||
5a2d0affc1 | |||
5afafecc23 | |||
07bf24911d | |||
357747d2fc | |||
28f6ffbc42 | |||
fb75eee385 | |||
6e2fb03b7b | |||
46d43d70b3 | |||
407579ca58 | |||
96df1a709f |
@ -3,36 +3,31 @@
|
|||||||
### Building osslsigncode source with MSYS2 MinGW 64-bit and MSYS2 packages:
|
### Building osslsigncode source with MSYS2 MinGW 64-bit and MSYS2 packages:
|
||||||
|
|
||||||
1) Download and install MSYS2 from https://msys2.github.io/ and follow installation instructions.
|
1) Download and install MSYS2 from https://msys2.github.io/ and follow installation instructions.
|
||||||
Once up and running install even mingw-w64-x86_64-gcc, mingw-w64-x86_64-curl, mingw-w64-x86_64-libgsf.
|
Once up and running install even mingw-w64-x86_64-gcc, mingw-w64-x86_64-curl.
|
||||||
```
|
```
|
||||||
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-curl mingw-w64-x86_64-libgsf
|
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-curl
|
||||||
```
|
```
|
||||||
mingw-w64-x86_64-openssl and mingw-w64-x86_64-zlib packages are installed with dependencies.
|
mingw-w64-x86_64-openssl and mingw-w64-x86_64-zlib packages are installed with dependencies.
|
||||||
|
|
||||||
2) Run "MSYS2 MinGW 64-bit" and build 64-bit Windows executables.
|
2) Run "MSYS2 MinGW 64-bit" and build 64-bit Windows executables.
|
||||||
```
|
```
|
||||||
cd osslsigncode-folder
|
cd osslsigncode-folder
|
||||||
x86_64-w64-mingw32-gcc osslsigncode.c msi.c -o osslsigncode.exe \
|
x86_64-w64-mingw32-gcc osslsigncode.c msi.c msi.h -o osslsigncode.exe \
|
||||||
-lcrypto -lssl -lcurl -lgsf-1 -lgobject-2.0 -lglib-2.0 -lxml2 \
|
-lcrypto -lssl -lcurl \
|
||||||
-I 'C:/msys64/mingw64/include/libgsf-1' \
|
-D 'PACKAGE_STRING="osslsigncode 2.3"' \
|
||||||
-I 'C:/msys64/mingw64/include/glib-2.0' \
|
|
||||||
-I 'C:/msys64/mingw64/lib/glib-2.0/include' \
|
|
||||||
-D 'PACKAGE_STRING="osslsigncode 2.1.0"' \
|
|
||||||
-D 'PACKAGE_BUGREPORT="Michal.Trojnara@stunnel.org"' \
|
-D 'PACKAGE_BUGREPORT="Michal.Trojnara@stunnel.org"' \
|
||||||
-D ENABLE_CURL \
|
-D ENABLE_CURL
|
||||||
-D WITH_GSF
|
|
||||||
```
|
```
|
||||||
|
|
||||||
3) Run "Command prompt" and include "c:\msys64\mingw64\bin" folder as part of the path.
|
3) Run "Command prompt" and include "c:\msys64\mingw64\bin" folder as part of the path.
|
||||||
```
|
```
|
||||||
path=%path%;c:\msys64\mingw64\bin
|
path=%path%;c:\msys64\mingw64\bin
|
||||||
cd osslsigncode-folder
|
cd osslsigncode-folder
|
||||||
|
|
||||||
osslsigncode.exe -v
|
osslsigncode.exe -v
|
||||||
osslsigncode 2.1.0, using:
|
osslsigncode 2.3, using:
|
||||||
OpenSSL 1.1.1g 21 Apr 2020
|
OpenSSL 1.1.1g 21 Apr 2020 (Library: OpenSSL 1.1.1g 21 Apr 2020)
|
||||||
libcurl/7.70.0 OpenSSL/1.1.1g (Schannel) zlib/1.2.11 brotli/1.0.7 libidn2/2.3.0
|
libcurl/7.70.0 OpenSSL/1.1.1g (Schannel) zlib/1.2.11 brotli/1.0.7 libidn2/2.3.0
|
||||||
libpsl/0.21.0 (+libidn2/2.3.0) libssh2/1.9.0 nghttp2/1.40.0 libgsf 1.14.46
|
libpsl/0.21.0 (+libidn2/2.3.0) libssh2/1.9.0 nghttp2/1.40.0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@ -68,19 +63,20 @@
|
|||||||
--disable-ftp --disable-tftp --disable-file --disable-dict \
|
--disable-ftp --disable-tftp --disable-file --disable-dict \
|
||||||
--disable-telnet --disable-imap --disable-smb --disable-smtp \
|
--disable-telnet --disable-imap --disable-smb --disable-smtp \
|
||||||
--disable-gopher --disable-pop --disable-pop3 --disable-rtsp \
|
--disable-gopher --disable-pop --disable-pop3 --disable-rtsp \
|
||||||
--disable-ldap --disable-ldaps --disable-unix-sockets --disable-pthreads
|
--disable-ldap --disable-ldaps --disable-unix-sockets \
|
||||||
|
--disable-pthreads --without-zstd
|
||||||
make && make install
|
make && make install
|
||||||
```
|
```
|
||||||
|
|
||||||
3) Build 64-bit Windows executables.
|
3) Build 64-bit Windows executables.
|
||||||
```
|
```
|
||||||
cd osslsigncode-folder
|
cd osslsigncode-folder
|
||||||
x86_64-w64-mingw32-gcc osslsigncode.c -o osslsigncode.exe \
|
x86_64-w64-mingw32-gcc osslsigncode.c msi.c msi.h -o osslsigncode.exe \
|
||||||
-L 'C:/OpenSSL/lib/' -lcrypto -lssl \
|
-L 'C:/OpenSSL/lib/' -lcrypto -lssl \
|
||||||
-I 'C:/OpenSSL/include/' \
|
-I 'C:/OpenSSL/include/' \
|
||||||
-L 'C:/curl/lib' -lcurl \
|
-L 'C:/curl/lib' -lcurl \
|
||||||
-I 'C:/curl/include' \
|
-I 'C:/curl/include' \
|
||||||
-D 'PACKAGE_STRING="osslsigncode 2.1.0"' \
|
-D 'PACKAGE_STRING="osslsigncode 2.3"' \
|
||||||
-D 'PACKAGE_BUGREPORT="Michal.Trojnara@stunnel.org"' \
|
-D 'PACKAGE_BUGREPORT="Michal.Trojnara@stunnel.org"' \
|
||||||
-D ENABLE_CURL
|
-D ENABLE_CURL
|
||||||
```
|
```
|
||||||
@ -94,8 +90,7 @@
|
|||||||
copy C:\msys64\mingw64\bin\zlib1.dll
|
copy C:\msys64\mingw64\bin\zlib1.dll
|
||||||
|
|
||||||
osslsigncode.exe -v
|
osslsigncode.exe -v
|
||||||
osslsigncode 2.1.0, using:
|
osslsigncode 2.3, using:
|
||||||
OpenSSL 1.1.1g 21 Apr 2020
|
OpenSSL 1.1.1k 25 Mar 2021 (Library: OpenSSL 1.1.1k 25 Mar 2021)
|
||||||
libcurl/7.70.0 OpenSSL/1.1.1g zlib/1.2.11
|
libcurl/7.78.0 OpenSSL/1.1.1k zlib/1.2.11
|
||||||
no libgsf available
|
|
||||||
```
|
```
|
||||||
|
@ -14,3 +14,8 @@ bin_PROGRAMS = osslsigncode
|
|||||||
|
|
||||||
osslsigncode_SOURCES = osslsigncode.c msi.c msi.h
|
osslsigncode_SOURCES = osslsigncode.c msi.c msi.h
|
||||||
osslsigncode_LDADD = $(OPENSSL_LIBS) $(OPTIONAL_LIBCURL_LIBS)
|
osslsigncode_LDADD = $(OPENSSL_LIBS) $(OPTIONAL_LIBCURL_LIBS)
|
||||||
|
|
||||||
|
# bash completion script
|
||||||
|
AM_DISTCHECK_CONFIGURE_FLAGS = --with-bashcompdir='$$(datarootdir)/bash-completion/completions'
|
||||||
|
bashcompdir = @bashcompdir@
|
||||||
|
dist_bashcomp_DATA = osslsigncode.bash
|
||||||
|
17
NEWS.md
17
NEWS.md
@ -1,3 +1,20 @@
|
|||||||
|
# osslsigncode change log
|
||||||
|
|
||||||
|
### 2.3 (2022.03.06)
|
||||||
|
|
||||||
|
**CRITICAL SECURITY VULNERABILITIES**
|
||||||
|
|
||||||
|
This release fixes several critical memory corruption vulnerabilities.
|
||||||
|
A malicious attacker could create a file, which, when processed with
|
||||||
|
osslsigncode, triggers arbitrary code execution. Any previous version
|
||||||
|
of osslsigncode should be immediately upgraded if the tool is used for
|
||||||
|
processing of untrusted files.
|
||||||
|
|
||||||
|
- fixed several memory safety issues
|
||||||
|
- fixed non-interactive PVK (MSBLOB) key decryption
|
||||||
|
- added a bash completion script
|
||||||
|
- added CA bundle path auto-detection
|
||||||
|
|
||||||
### 2.2 (2021.08.15)
|
### 2.2 (2021.08.15)
|
||||||
|
|
||||||
- CAT files support (thanks to James McKenzie)
|
- CAT files support (thanks to James McKenzie)
|
||||||
|
21
configure.ac
21
configure.ac
@ -1,12 +1,21 @@
|
|||||||
AC_PREREQ(2.60)
|
AC_PREREQ(2.60)
|
||||||
|
|
||||||
AC_INIT([osslsigncode], [2.2.0], [Michal.Trojnara@stunnel.org])
|
AC_INIT([osslsigncode], [2.3.0], [Michal.Trojnara@stunnel.org])
|
||||||
AC_CONFIG_AUX_DIR([.])
|
AC_CONFIG_AUX_DIR([.])
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
AM_INIT_AUTOMAKE
|
AM_INIT_AUTOMAKE
|
||||||
|
|
||||||
AC_CONFIG_SRCDIR([osslsigncode.c])
|
AC_CONFIG_SRCDIR([osslsigncode.c])
|
||||||
|
|
||||||
|
# bash completion support
|
||||||
|
AC_ARG_WITH([bashcompdir],
|
||||||
|
AS_HELP_STRING([--with-bashcompdir=DIR], [directory for bash completions]), ,
|
||||||
|
[PKG_CHECK_VAR([with_bashcompdir], [bash-completion], [completionsdir], ,
|
||||||
|
[with_bashcompdir="${datarootdir}/bash-completion/completions"])])
|
||||||
|
AC_MSG_CHECKING([for bashcompdir])
|
||||||
|
AC_MSG_RESULT([$with_bashcompdir])
|
||||||
|
AC_SUBST([bashcompdir], [$with_bashcompdir])
|
||||||
|
|
||||||
dnl Checks for programs.
|
dnl Checks for programs.
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
AC_USE_SYSTEM_EXTENSIONS
|
AC_USE_SYSTEM_EXTENSIONS
|
||||||
@ -109,7 +118,13 @@ PKG_CHECK_MODULES(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if test "${with_curl}" = "yes"; then
|
if test "${with_curl}" = "yes"; then
|
||||||
test -z "${LIBCURL_LIBS}" && AC_MSG_ERROR([Curl 7.12.0 or later is required for timestamping support. http://curl.haxx.se/])
|
test -z "${LIBCURL_LIBS}" && AC_MSG_ERROR(m4_normalize([
|
||||||
|
Curl 7.12.0 or later required for timestamping support http://curl.haxx.se/
|
||||||
|
m4_newline() or libcurl development package not found, try installing:
|
||||||
|
m4_newline() * libcurl4-openssl-dev (Debian, Ubuntu)
|
||||||
|
m4_newline() * libcurl-devel (Fedora, CentOS, RHEL)
|
||||||
|
m4_newline() * libcurl_dev (Solaris)
|
||||||
|
]))
|
||||||
OPTIONAL_LIBCURL_CFLAGS="${LIBCURL_CFLAGS}"
|
OPTIONAL_LIBCURL_CFLAGS="${LIBCURL_CFLAGS}"
|
||||||
OPTIONAL_LIBCURL_LIBS="${LIBCURL_LIBS}"
|
OPTIONAL_LIBCURL_LIBS="${LIBCURL_LIBS}"
|
||||||
AC_DEFINE([ENABLE_CURL], [1], [libcurl is enabled])
|
AC_DEFINE([ENABLE_CURL], [1], [libcurl is enabled])
|
||||||
@ -118,8 +133,6 @@ fi
|
|||||||
AC_SUBST([OPTIONAL_LIBCURL_CFLAGS])
|
AC_SUBST([OPTIONAL_LIBCURL_CFLAGS])
|
||||||
AC_SUBST([OPTIONAL_LIBCURL_LIBS])
|
AC_SUBST([OPTIONAL_LIBCURL_LIBS])
|
||||||
|
|
||||||
AC_DEFINE_UNQUOTED([CA_BUNDLE_PATH], ["$(curl-config --ca 2>/dev/null)"], [CA bundle install path])
|
|
||||||
|
|
||||||
AC_CONFIG_FILES([Makefile])
|
AC_CONFIG_FILES([Makefile])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
||||||
|
417
msi.c
417
msi.c
@ -15,19 +15,22 @@
|
|||||||
|
|
||||||
#define MIN(a,b) ((a) < (b) ? a : b)
|
#define MIN(a,b) ((a) < (b) ? a : b)
|
||||||
|
|
||||||
|
static int recurse_entry(MSI_FILE *msi, uint32_t entryID, MSI_DIRENT *parent);
|
||||||
|
|
||||||
/* Get absolute address from sector and offset */
|
/* Get absolute address from sector and offset */
|
||||||
static const u_char *sector_offset_to_address(MSI_FILE *msi, size_t sector, size_t offset)
|
static const u_char *sector_offset_to_address(MSI_FILE *msi, uint32_t sector, uint32_t offset)
|
||||||
{
|
{
|
||||||
if (sector >= MAXREGSECT || offset >= msi->m_sectorSize ||
|
if (sector >= MAXREGSECT || offset >= msi->m_sectorSize
|
||||||
msi->m_bufferLen <= msi->m_sectorSize * sector + msi->m_sectorSize + offset) {
|
|| (msi->m_bufferLen - offset) / msi->m_sectorSize <= sector) {
|
||||||
|
printf("Corrupted file\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
return msi->m_buffer + msi->m_sectorSize + msi->m_sectorSize * sector + offset;
|
return msi->m_buffer + (sector + 1) * msi->m_sectorSize + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t get_fat_sector_location(MSI_FILE *msi, size_t fatSectorNumber)
|
static uint32_t get_fat_sector_location(MSI_FILE *msi, uint32_t fatSectorNumber)
|
||||||
{
|
{
|
||||||
size_t entriesPerSector, difatSectorLocation;
|
uint32_t entriesPerSector, difatSectorLocation;
|
||||||
const u_char *address;
|
const u_char *address;
|
||||||
|
|
||||||
if (fatSectorNumber < DIFAT_IN_HEADER) {
|
if (fatSectorNumber < DIFAT_IN_HEADER) {
|
||||||
@ -39,40 +42,68 @@ static size_t get_fat_sector_location(MSI_FILE *msi, size_t fatSectorNumber)
|
|||||||
while (fatSectorNumber >= entriesPerSector) {
|
while (fatSectorNumber >= entriesPerSector) {
|
||||||
fatSectorNumber -= entriesPerSector;
|
fatSectorNumber -= entriesPerSector;
|
||||||
address = sector_offset_to_address(msi, difatSectorLocation, msi->m_sectorSize - 4);
|
address = sector_offset_to_address(msi, difatSectorLocation, msi->m_sectorSize - 4);
|
||||||
|
if (!address) {
|
||||||
|
printf("Failed to get a next sector address\n");
|
||||||
|
return NOSTREAM; /* FAILED */
|
||||||
|
}
|
||||||
difatSectorLocation = GET_UINT32_LE(address);
|
difatSectorLocation = GET_UINT32_LE(address);
|
||||||
}
|
}
|
||||||
return GET_UINT32_LE(sector_offset_to_address(msi, difatSectorLocation, fatSectorNumber * 4));
|
address = sector_offset_to_address(msi, difatSectorLocation, fatSectorNumber * 4);
|
||||||
|
if (!address) {
|
||||||
|
printf("Failed to get a next sector address\n");
|
||||||
|
return NOSTREAM; /* FAILED */
|
||||||
|
}
|
||||||
|
return GET_UINT32_LE(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Lookup FAT */
|
/* Lookup FAT */
|
||||||
static size_t get_next_sector(MSI_FILE *msi, size_t sector)
|
static uint32_t get_next_sector(MSI_FILE *msi, uint32_t sector)
|
||||||
{
|
{
|
||||||
size_t entriesPerSector = msi->m_sectorSize / 4;
|
const u_char *address;
|
||||||
size_t fatSectorNumber = sector / entriesPerSector;
|
uint32_t entriesPerSector = msi->m_sectorSize / 4;
|
||||||
size_t fatSectorLocation = get_fat_sector_location(msi, fatSectorNumber);
|
uint32_t fatSectorNumber = sector / entriesPerSector;
|
||||||
return GET_UINT32_LE(sector_offset_to_address(msi, fatSectorLocation, sector % entriesPerSector * 4));
|
uint32_t fatSectorLocation = get_fat_sector_location(msi, fatSectorNumber);
|
||||||
|
if (fatSectorLocation == NOSTREAM) {
|
||||||
|
printf("Failed to get a fat sector location\n");
|
||||||
|
return NOSTREAM; /* FAILED */
|
||||||
|
}
|
||||||
|
address = sector_offset_to_address(msi, fatSectorLocation, sector % entriesPerSector * 4);
|
||||||
|
if (!address) {
|
||||||
|
printf("Failed to get a next sector address\n");
|
||||||
|
return NOSTREAM; /* FAILED */
|
||||||
|
}
|
||||||
|
return GET_UINT32_LE(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Locate the final sector/offset when original offset expands multiple sectors */
|
/* Locate the final sector/offset when original offset expands multiple sectors */
|
||||||
static void locate_final_sector(MSI_FILE *msi, size_t sector, size_t offset, size_t *finalSector, size_t *finalOffset)
|
static int locate_final_sector(MSI_FILE *msi, uint32_t sector, uint32_t offset, uint32_t *finalSector, uint32_t *finalOffset)
|
||||||
{
|
{
|
||||||
while (offset >= msi->m_sectorSize) {
|
while (offset >= msi->m_sectorSize) {
|
||||||
offset -= msi->m_sectorSize;
|
offset -= msi->m_sectorSize;
|
||||||
sector = get_next_sector(msi, sector);
|
sector = get_next_sector(msi, sector);
|
||||||
|
if (sector == NOSTREAM) {
|
||||||
|
printf("Failed to get a next sector\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*finalSector = sector;
|
*finalSector = sector;
|
||||||
*finalOffset = offset;
|
*finalOffset = offset;
|
||||||
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get absolute address from mini sector and offset */
|
/* Get absolute address from mini sector and offset */
|
||||||
static const u_char *mini_sector_offset_to_address(MSI_FILE *msi, size_t sector, size_t offset)
|
static const u_char *mini_sector_offset_to_address(MSI_FILE *msi, uint32_t sector, uint32_t offset)
|
||||||
{
|
{
|
||||||
if (sector >= MAXREGSECT || offset >= msi->m_minisectorSize ||
|
if (sector >= MAXREGSECT || offset >= msi->m_minisectorSize ||
|
||||||
msi->m_bufferLen <= msi->m_minisectorSize * sector + offset) {
|
(msi->m_bufferLen - offset) / msi->m_minisectorSize <= sector) {
|
||||||
|
printf("Corrupted file\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
if (!locate_final_sector(msi, msi->m_miniStreamStartSector, sector * msi->m_minisectorSize + offset, §or, &offset)) {
|
||||||
|
printf("Failed to locate a final sector\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
locate_final_sector(msi, msi->m_miniStreamStartSector, sector * msi->m_minisectorSize + offset, §or, &offset);
|
|
||||||
return sector_offset_to_address(msi, sector, offset);
|
return sector_offset_to_address(msi, sector, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,66 +111,109 @@ static const u_char *mini_sector_offset_to_address(MSI_FILE *msi, size_t sector,
|
|||||||
* Copy as many as possible in each step
|
* Copy as many as possible in each step
|
||||||
* copylen typically iterate as: msi->m_sectorSize - offset --> msi->m_sectorSize --> msi->m_sectorSize --> ... --> remaining
|
* copylen typically iterate as: msi->m_sectorSize - offset --> msi->m_sectorSize --> msi->m_sectorSize --> ... --> remaining
|
||||||
*/
|
*/
|
||||||
static int read_stream(MSI_FILE *msi, size_t sector, size_t offset, char *buffer, size_t len)
|
static int read_stream(MSI_FILE *msi, uint32_t sector, uint32_t offset, char *buffer, uint32_t len)
|
||||||
{
|
{
|
||||||
locate_final_sector(msi, sector, offset, §or, &offset);
|
if (!locate_final_sector(msi, sector, offset, §or, &offset)) {
|
||||||
|
printf("Failed to locate a final sector\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
const u_char *address = sector_offset_to_address(msi, sector, offset);
|
const u_char *address;
|
||||||
size_t copylen = MIN(len, msi->m_sectorSize - offset);
|
uint32_t copylen;
|
||||||
|
address = sector_offset_to_address(msi, sector, offset);
|
||||||
|
if (!address) {
|
||||||
|
printf("Failed to get a next sector address\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
copylen = MIN(len, msi->m_sectorSize - offset);
|
||||||
if (msi->m_buffer + msi->m_bufferLen < address + copylen) {
|
if (msi->m_buffer + msi->m_bufferLen < address + copylen) {
|
||||||
|
printf("Corrupted file\n");
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
memcpy(buffer, address, copylen);
|
memcpy(buffer, address, copylen);
|
||||||
buffer += copylen;
|
buffer += copylen;
|
||||||
len -= copylen;
|
len -= copylen;
|
||||||
sector = get_next_sector(msi, sector);
|
sector = get_next_sector(msi, sector);
|
||||||
|
if (sector == 0) {
|
||||||
|
printf("Failed to get a next sector\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Lookup miniFAT */
|
/* Lookup miniFAT */
|
||||||
static size_t get_next_mini_sector(MSI_FILE *msi, size_t miniSector)
|
static uint32_t get_next_mini_sector(MSI_FILE *msi, uint32_t miniSector)
|
||||||
{
|
{
|
||||||
size_t sector, offset;
|
uint32_t sector, offset;
|
||||||
locate_final_sector(msi, msi->m_hdr->firstMiniFATSectorLocation, miniSector * 4, §or, &offset);
|
const u_char *address;
|
||||||
return GET_UINT32_LE(sector_offset_to_address(msi, sector, offset));
|
|
||||||
|
if (!locate_final_sector(msi, msi->m_hdr->firstMiniFATSectorLocation, miniSector * 4, §or, &offset)) {
|
||||||
|
printf("Failed to locate a final sector\n");
|
||||||
|
return NOSTREAM; /* FAILED */
|
||||||
|
}
|
||||||
|
address = sector_offset_to_address(msi, sector, offset);
|
||||||
|
if (!address) {
|
||||||
|
printf("Failed to get a next mini sector address\n");
|
||||||
|
return NOSTREAM; /* FAILED */
|
||||||
|
}
|
||||||
|
return GET_UINT32_LE(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void locate_final_mini_sector(MSI_FILE *msi, size_t sector, size_t offset, size_t *finalSector, size_t *finalOffset)
|
static int locate_final_mini_sector(MSI_FILE *msi, uint32_t sector, uint32_t offset, uint32_t *finalSector, uint32_t *finalOffset)
|
||||||
{
|
{
|
||||||
while (offset >= msi->m_minisectorSize) {
|
while (offset >= msi->m_minisectorSize) {
|
||||||
offset -= msi->m_minisectorSize;
|
offset -= msi->m_minisectorSize;
|
||||||
sector = get_next_mini_sector(msi, sector);
|
sector = get_next_mini_sector(msi, sector);
|
||||||
|
if (sector == NOSTREAM) {
|
||||||
|
printf("Failed to get a next mini sector\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*finalSector = sector;
|
*finalSector = sector;
|
||||||
*finalOffset = offset;
|
*finalOffset = offset;
|
||||||
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Same logic as "read_stream" except that use mini stream functions instead */
|
/* Same logic as "read_stream" except that use mini stream functions instead */
|
||||||
static int read_mini_stream(MSI_FILE *msi, size_t sector, size_t offset, char *buffer, size_t len)
|
static int read_mini_stream(MSI_FILE *msi, uint32_t sector, uint32_t offset, char *buffer, uint32_t len)
|
||||||
{
|
{
|
||||||
locate_final_mini_sector(msi, sector, offset, §or, &offset);
|
if (!locate_final_mini_sector(msi, sector, offset, §or, &offset)) {
|
||||||
|
printf("Failed to locate a final mini sector\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
const u_char *address = mini_sector_offset_to_address(msi, sector, offset);
|
const u_char *address;
|
||||||
size_t copylen = MIN(len, msi->m_minisectorSize - offset);
|
uint32_t copylen;
|
||||||
if (!address || msi->m_buffer + msi->m_bufferLen < address + copylen) {
|
address = mini_sector_offset_to_address(msi, sector, offset);
|
||||||
|
if (!address) {
|
||||||
|
printf("Failed to get a next mini sector address\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
copylen = MIN(len, msi->m_minisectorSize - offset);
|
||||||
|
if (msi->m_buffer + msi->m_bufferLen < address + copylen) {
|
||||||
|
printf("Corrupted file\n");
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
memcpy(buffer, address, copylen);
|
memcpy(buffer, address, copylen);
|
||||||
buffer += copylen;
|
buffer += copylen;
|
||||||
len -= copylen;
|
len -= copylen;
|
||||||
sector = get_next_mini_sector(msi, sector);
|
sector = get_next_mini_sector(msi, sector);
|
||||||
|
if (sector == NOSTREAM) {
|
||||||
|
printf("Failed to get a next mini sector\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get file (stream) data start with "offset".
|
* Get file (stream) data start with "offset".
|
||||||
* The buffer must have enough space to store "len" bytes. Typically "len" is derived by the steam length.
|
* The buffer must have enough space to store "len" bytes. Typically "len" is derived by the steam length.
|
||||||
*/
|
*/
|
||||||
int msi_file_read(MSI_FILE *msi, MSI_ENTRY *entry, size_t offset, char *buffer, size_t len)
|
int msi_file_read(MSI_FILE *msi, MSI_ENTRY *entry, uint32_t offset, char *buffer, uint32_t len)
|
||||||
{
|
{
|
||||||
if (len < msi->m_hdr->miniStreamCutoffSize) {
|
if (len < msi->m_hdr->miniStreamCutoffSize) {
|
||||||
if (!read_mini_stream(msi, entry->startSectorLocation, offset, buffer, len))
|
if (!read_mini_stream(msi, entry->startSectorLocation, offset, buffer, len))
|
||||||
@ -148,43 +222,108 @@ int msi_file_read(MSI_FILE *msi, MSI_ENTRY *entry, size_t offset, char *buffer,
|
|||||||
if (!read_stream(msi, entry->startSectorLocation, offset, buffer, len))
|
if (!read_stream(msi, entry->startSectorLocation, offset, buffer, len))
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
return 1;
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse MSI_FILE_HDR struct */
|
/* Parse MSI_FILE_HDR struct */
|
||||||
static MSI_FILE_HDR *parse_header(char *data)
|
static MSI_FILE_HDR *parse_header(char *data)
|
||||||
{
|
{
|
||||||
MSI_FILE_HDR *header = (MSI_FILE_HDR *)OPENSSL_malloc(HEADER_SIZE);
|
MSI_FILE_HDR *header = (MSI_FILE_HDR *)OPENSSL_malloc(HEADER_SIZE);
|
||||||
if (!data) {
|
|
||||||
/* initialise 512 bytes */
|
/* initialise 512 bytes */
|
||||||
memset(header, 0, sizeof(MSI_FILE_HDR));
|
memset(header, 0, sizeof(MSI_FILE_HDR));
|
||||||
} else {
|
|
||||||
memcpy(header->signature, data + HEADER_SIGNATURE, sizeof header->signature);
|
memcpy(header->signature, data + HEADER_SIGNATURE, sizeof header->signature);
|
||||||
|
/* Minor Version field SHOULD be set to 0x003E. */
|
||||||
header->minorVersion = GET_UINT16_LE(data + HEADER_MINOR_VER);
|
header->minorVersion = GET_UINT16_LE(data + HEADER_MINOR_VER);
|
||||||
|
if (header->minorVersion !=0x003E ) {
|
||||||
|
printf("Warning: Minor Version field SHOULD be 0x003E, but is: 0x%04X\n", header->minorVersion);
|
||||||
|
}
|
||||||
|
/* Major Version field MUST be set to either 0x0003 (version 3) or 0x0004 (version 4). */
|
||||||
header->majorVersion = GET_UINT16_LE(data + HEADER_MAJOR_VER);
|
header->majorVersion = GET_UINT16_LE(data + HEADER_MAJOR_VER);
|
||||||
|
if (header->majorVersion != 0x0003 && header->majorVersion != 0x0004) {
|
||||||
|
printf("Unknown Major Version: 0x%04X\n", header->majorVersion);
|
||||||
|
OPENSSL_free(header);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
/* Byte Order field MUST be set to 0xFFFE, specifies little-endian byte order. */
|
||||||
header->byteOrder = GET_UINT16_LE(data + HEADER_BYTE_ORDER);
|
header->byteOrder = GET_UINT16_LE(data + HEADER_BYTE_ORDER);
|
||||||
|
if (header->byteOrder != 0xFFFE) {
|
||||||
|
printf("Unknown Byte Order: 0x%04X\n", header->byteOrder);
|
||||||
|
OPENSSL_free(header);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
/* Sector Shift field MUST be set to 0x0009, or 0x000c, depending on the Major Version field.
|
||||||
|
* This field specifies the sector size of the compound file as a power of 2. */
|
||||||
header->sectorShift = GET_UINT16_LE(data + HEADER_SECTOR_SHIFT);
|
header->sectorShift = GET_UINT16_LE(data + HEADER_SECTOR_SHIFT);
|
||||||
|
if ((header->majorVersion == 0x0003 && header->sectorShift != 0x0009) ||
|
||||||
|
(header->majorVersion == 0x0004 && header->sectorShift != 0x000C)) {
|
||||||
|
printf("Unknown Sector Shift: 0x%04X\n", header->sectorShift);
|
||||||
|
OPENSSL_free(header);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
/* Mini Sector Shift field MUST be set to 0x0006.
|
||||||
|
* This field specifies the sector size of the Mini Stream as a power of 2.
|
||||||
|
* The sector size of the Mini Stream MUST be 64 bytes. */
|
||||||
header->miniSectorShift = GET_UINT16_LE(data + HEADER_MINI_SECTOR_SHIFT);
|
header->miniSectorShift = GET_UINT16_LE(data + HEADER_MINI_SECTOR_SHIFT);
|
||||||
|
if (header->miniSectorShift != 0x0006) {
|
||||||
|
printf("Unknown Mini Sector Shift: 0x%04X\n", header->miniSectorShift);
|
||||||
|
OPENSSL_free(header);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
/* Number of Directory Sectors field contains the count of the number
|
||||||
|
* of directory sectors in the compound file.
|
||||||
|
* If Major Version is 3, the Number of Directory Sectors MUST be zero. */
|
||||||
header->numDirectorySector = GET_UINT32_LE(data + HEADER_DIR_SECTORS_NUM);
|
header->numDirectorySector = GET_UINT32_LE(data + HEADER_DIR_SECTORS_NUM);
|
||||||
|
if (header->majorVersion == 0x0003 && header->numDirectorySector != 0x00000000) {
|
||||||
|
printf("Unsupported Number of Directory Sectors: 0x%08X\n", header->numDirectorySector);
|
||||||
|
OPENSSL_free(header);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
header->numFATSector = GET_UINT32_LE(data + HEADER_FAT_SECTORS_NUM);
|
header->numFATSector = GET_UINT32_LE(data + HEADER_FAT_SECTORS_NUM);
|
||||||
header->firstDirectorySectorLocation = GET_UINT32_LE(data + HEADER_DIR_SECTOR_LOC);
|
header->firstDirectorySectorLocation = GET_UINT32_LE(data + HEADER_DIR_SECTOR_LOC);
|
||||||
header->transactionSignatureNumber = GET_UINT32_LE(data + HEADER_TRANSACTION);
|
header->transactionSignatureNumber = GET_UINT32_LE(data + HEADER_TRANSACTION);
|
||||||
|
/* Mini Stream Cutoff Size field MUST be set to 0x00001000.
|
||||||
|
* This field specifies the maximum size of a user-defined data stream that is allocated
|
||||||
|
* from the mini FAT and mini stream, and that cutoff is 4,096 bytes.
|
||||||
|
* Any user-defined data stream that is greater than or equal to this cutoff size
|
||||||
|
* must be allocated as normal sectors from the FAT. */
|
||||||
header->miniStreamCutoffSize = GET_UINT32_LE(data + HEADER_MINI_STREAM_CUTOFF);
|
header->miniStreamCutoffSize = GET_UINT32_LE(data + HEADER_MINI_STREAM_CUTOFF);
|
||||||
|
if (header->miniStreamCutoffSize != 0x00001000) {
|
||||||
|
printf("Unsupported Mini Stream Cutoff Size: 0x%08X\n", header->miniStreamCutoffSize);
|
||||||
|
OPENSSL_free(header);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
header->firstMiniFATSectorLocation = GET_UINT32_LE(data + HEADER_MINI_FAT_SECTOR_LOC);
|
header->firstMiniFATSectorLocation = GET_UINT32_LE(data + HEADER_MINI_FAT_SECTOR_LOC);
|
||||||
header->numMiniFATSector = GET_UINT32_LE(data + HEADER_MINI_FAT_SECTORS_NUM);
|
header->numMiniFATSector = GET_UINT32_LE(data + HEADER_MINI_FAT_SECTORS_NUM);
|
||||||
header->firstDIFATSectorLocation = GET_UINT32_LE(data + HEADER_DIFAT_SECTOR_LOC);
|
header->firstDIFATSectorLocation = GET_UINT32_LE(data + HEADER_DIFAT_SECTOR_LOC);
|
||||||
header->numDIFATSector = GET_UINT32_LE(data + HEADER_DIFAT_SECTORS_NUM);
|
header->numDIFATSector = GET_UINT32_LE(data + HEADER_DIFAT_SECTORS_NUM);
|
||||||
memcpy(header->headerDIFAT, data + HEADER_DIFAT, sizeof header->headerDIFAT);
|
memcpy(header->headerDIFAT, data + HEADER_DIFAT, sizeof header->headerDIFAT);
|
||||||
}
|
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse MSI_ENTRY struct */
|
/* Parse MSI_ENTRY struct */
|
||||||
static MSI_ENTRY *parse_entry(const u_char *data)
|
static MSI_ENTRY *parse_entry(MSI_FILE *msi, const u_char *data, int is_root)
|
||||||
{
|
{
|
||||||
|
uint32_t inlen;
|
||||||
MSI_ENTRY *entry = (MSI_ENTRY *)OPENSSL_malloc(sizeof(MSI_ENTRY));
|
MSI_ENTRY *entry = (MSI_ENTRY *)OPENSSL_malloc(sizeof(MSI_ENTRY));
|
||||||
|
|
||||||
|
/* initialise 128 bytes */
|
||||||
|
memset(entry, 0, sizeof(MSI_ENTRY));
|
||||||
entry->nameLen = GET_UINT16_LE(data + DIRENT_NAME_LEN);
|
entry->nameLen = GET_UINT16_LE(data + DIRENT_NAME_LEN);
|
||||||
|
/* This length MUST NOT exceed 64, the maximum size of the Directory Entry Name field */
|
||||||
|
if (entry->nameLen == 0 || entry->nameLen > 64) {
|
||||||
|
printf("Corrupted Directory Entry Name Length\n");
|
||||||
|
OPENSSL_free(entry);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
memcpy(entry->name, data + DIRENT_NAME, entry->nameLen);
|
memcpy(entry->name, data + DIRENT_NAME, entry->nameLen);
|
||||||
|
/* The root directory entry's Name field MUST contain the null-terminated
|
||||||
|
* string "Root Entry" in Unicode UTF-16. */
|
||||||
|
if (is_root && memcmp(entry->name, msi_root_entry, entry->nameLen)) {
|
||||||
|
printf("Corrupted Root Directory Entry's Name\n");
|
||||||
|
OPENSSL_free(entry);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
entry->type = GET_UINT8_LE(data + DIRENT_TYPE);
|
entry->type = GET_UINT8_LE(data + DIRENT_TYPE);
|
||||||
entry->colorFlag = GET_UINT8_LE(data + DIRENT_COLOUR);
|
entry->colorFlag = GET_UINT8_LE(data + DIRENT_COLOUR);
|
||||||
entry->leftSiblingID = GET_UINT32_LE(data + DIRENT_LEFT_SIBLING_ID);
|
entry->leftSiblingID = GET_UINT32_LE(data + DIRENT_LEFT_SIBLING_ID);
|
||||||
@ -193,9 +332,25 @@ static MSI_ENTRY *parse_entry(const u_char *data)
|
|||||||
memcpy(entry->clsid, data + DIRENT_CLSID, 16);
|
memcpy(entry->clsid, data + DIRENT_CLSID, 16);
|
||||||
memcpy(entry->stateBits, data + DIRENT_STATE_BITS, 4);
|
memcpy(entry->stateBits, data + DIRENT_STATE_BITS, 4);
|
||||||
memcpy(entry->creationTime, data + DIRENT_CREATE_TIME, 8);
|
memcpy(entry->creationTime, data + DIRENT_CREATE_TIME, 8);
|
||||||
|
/* The Creation Time field in the root storage directory entry MUST be all zeroes
|
||||||
|
but the Modified Time field in the root storage directory entry MAY be all zeroes */
|
||||||
|
if (is_root && memcmp(entry->creationTime, msi_zeroes, 8)) {
|
||||||
|
printf("Corrupted Root Directory Entry's Creation Time\n");
|
||||||
|
OPENSSL_free(entry);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
memcpy(entry->modifiedTime, data + DIRENT_MODIFY_TIME, 8);
|
memcpy(entry->modifiedTime, data + DIRENT_MODIFY_TIME, 8);
|
||||||
entry->startSectorLocation = GET_UINT32_LE(data + DIRENT_START_SECTOR_LOC);
|
entry->startSectorLocation = GET_UINT32_LE(data + DIRENT_START_SECTOR_LOC);
|
||||||
memcpy(entry->size, data + DIRENT_FILE_SIZE, 8);
|
memcpy(entry->size, data + DIRENT_FILE_SIZE, 8);
|
||||||
|
/* For a version 3 compound file 512-byte sector size, the value of this field
|
||||||
|
MUST be less than or equal to 0x80000000 */
|
||||||
|
inlen = GET_UINT32_LE(entry->size);
|
||||||
|
if ((msi->m_sectorSize == 0x0200 && inlen > 0x80000000)
|
||||||
|
|| (msi->m_bufferLen <= inlen)) {
|
||||||
|
printf("Corrupted Stream Size 0x%08X\n", inlen);
|
||||||
|
OPENSSL_free(entry);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,63 +359,86 @@ static MSI_ENTRY *parse_entry(const u_char *data)
|
|||||||
* Pass "0" to get the root directory entry. -- This is the start point to navigate the compound file.
|
* Pass "0" to get the root directory entry. -- This is the start point to navigate the compound file.
|
||||||
* Use the returned object to access child entries.
|
* Use the returned object to access child entries.
|
||||||
*/
|
*/
|
||||||
static MSI_ENTRY *get_entry(MSI_FILE *msi, size_t entryID)
|
static MSI_ENTRY *get_entry(MSI_FILE *msi, uint32_t entryID, int is_root)
|
||||||
{
|
{
|
||||||
size_t sector = 0;
|
uint32_t sector = 0;
|
||||||
size_t offset = 0;
|
uint32_t offset = 0;
|
||||||
const u_char *address;
|
const u_char *address;
|
||||||
|
|
||||||
/* The special value NOSTREAM (0xFFFFFFFF) is used as a terminator */
|
/* Corrupted file */
|
||||||
if (entryID == NOSTREAM) {
|
if (!is_root && entryID == 0) {
|
||||||
|
printf("Corrupted entryID\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (msi->m_bufferLen / sizeof(MSI_ENTRY) <= entryID) {
|
if (msi->m_bufferLen / sizeof(MSI_ENTRY) <= entryID) {
|
||||||
printf("Invalid argument entryID\n");
|
printf("Invalid argument entryID\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
locate_final_sector(msi, msi->m_hdr->firstDirectorySectorLocation, entryID * sizeof(MSI_ENTRY), §or, &offset);
|
/* The first entry in the first sector of the directory chain is known as
|
||||||
|
the root directory entry so it can not contain the directory stream */
|
||||||
|
if (msi->m_hdr->firstDirectorySectorLocation == 0 && entryID == 0) {
|
||||||
|
printf("Corrupted First Directory Sector Location\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
if (!locate_final_sector(msi, msi->m_hdr->firstDirectorySectorLocation,
|
||||||
|
entryID * sizeof(MSI_ENTRY), §or, &offset)) {
|
||||||
|
printf("Failed to locate a final sector\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
address = sector_offset_to_address(msi, sector, offset);
|
address = sector_offset_to_address(msi, sector, offset);
|
||||||
return parse_entry(address);
|
if (!address) {
|
||||||
|
printf("Failed to get a final address\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
return parse_entry(msi, address, is_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
MSI_ENTRY *msi_root_entry_get(MSI_FILE *msi)
|
MSI_ENTRY *msi_root_entry_get(MSI_FILE *msi)
|
||||||
{
|
{
|
||||||
return get_entry(msi, 0);
|
return get_entry(msi, 0, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse MSI_FILE struct */
|
/* Parse MSI_FILE struct */
|
||||||
MSI_FILE *msi_file_new(char *buffer, size_t len)
|
MSI_FILE *msi_file_new(char *buffer, uint32_t len)
|
||||||
{
|
{
|
||||||
MSI_FILE *msi;
|
MSI_FILE *msi;
|
||||||
MSI_ENTRY *root;
|
MSI_ENTRY *root;
|
||||||
|
MSI_FILE_HDR *header;
|
||||||
|
|
||||||
if (buffer == NULL || len == 0) {
|
if (buffer == NULL || len == 0) {
|
||||||
printf("Invalid argument\n");
|
printf("Invalid argument\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
|
header = parse_header(buffer);
|
||||||
|
if (!header) {
|
||||||
|
printf("Failed to parse MSI_FILE_HDR struct\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
msi = (MSI_FILE *)OPENSSL_malloc(sizeof(MSI_FILE));
|
msi = (MSI_FILE *)OPENSSL_malloc(sizeof(MSI_FILE));
|
||||||
msi->m_buffer = (const u_char *)(buffer);
|
msi->m_buffer = (const u_char *)(buffer);
|
||||||
msi->m_bufferLen = len;
|
msi->m_bufferLen = len;
|
||||||
msi->m_hdr = parse_header(buffer);
|
msi->m_hdr = header;
|
||||||
msi->m_sectorSize = 1 << msi->m_hdr->sectorShift;;
|
msi->m_sectorSize = 1 << msi->m_hdr->sectorShift;
|
||||||
msi->m_minisectorSize = 1 << msi->m_hdr->miniSectorShift;
|
msi->m_minisectorSize = 1 << msi->m_hdr->miniSectorShift;
|
||||||
msi->m_miniStreamStartSector = 0;
|
msi->m_miniStreamStartSector = 0;
|
||||||
|
|
||||||
if (msi->m_bufferLen < sizeof *(msi->m_hdr) ||
|
if (msi->m_bufferLen < sizeof *(msi->m_hdr) ||
|
||||||
memcmp(msi->m_hdr->signature, msi_magic, sizeof msi_magic)) {
|
memcmp(msi->m_hdr->signature, msi_magic, sizeof msi_magic)) {
|
||||||
printf("Wrong file format\n");
|
printf("Wrong file format\n");
|
||||||
|
msi_file_free(msi);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
msi->m_sectorSize = msi->m_hdr->majorVersion == 3 ? 512 : 4096;
|
|
||||||
|
|
||||||
/* The file must contains at least 3 sectors */
|
/* The file must contains at least 3 sectors */
|
||||||
if (msi->m_bufferLen < msi->m_sectorSize * 3) {
|
if (msi->m_bufferLen < msi->m_sectorSize * 3) {
|
||||||
printf("The file must contains at least 3 sectors\n");
|
printf("The file must contains at least 3 sectors\n");
|
||||||
|
msi_file_free(msi);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
root = msi_root_entry_get(msi);
|
root = msi_root_entry_get(msi);
|
||||||
if (root == NULL) {
|
if (!root) {
|
||||||
printf("File corrupted\n");
|
printf("Failed to get msi root entry\n");
|
||||||
|
msi_file_free(msi);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
msi->m_miniStreamStartSector = root->startSectorLocation;
|
msi->m_miniStreamStartSector = root->startSectorLocation;
|
||||||
@ -268,37 +446,90 @@ MSI_FILE *msi_file_new(char *buffer, size_t len)
|
|||||||
return msi;
|
return msi;
|
||||||
}
|
}
|
||||||
|
|
||||||
MSI_FILE_HDR *msi_header_get(MSI_FILE *msi)
|
/* Recursively create a tree of MSI_DIRENT structures */
|
||||||
{
|
int msi_dirent_new(MSI_FILE *msi, MSI_ENTRY *entry, MSI_DIRENT *parent, MSI_DIRENT **ret)
|
||||||
return msi->m_hdr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Recursively parse MSI_DIRENT struct */
|
|
||||||
MSI_DIRENT *msi_dirent_new(MSI_FILE *msi, MSI_ENTRY *entry, MSI_DIRENT *parent)
|
|
||||||
{
|
{
|
||||||
MSI_DIRENT *dirent;
|
MSI_DIRENT *dirent;
|
||||||
|
static int cnt;
|
||||||
|
static MSI_DIRENT *tortoise, *hare;
|
||||||
|
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
return NULL;
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
|
if (entry->nameLen == 0 || entry->nameLen > 64) {
|
||||||
|
printf("Corrupted Directory Entry Name Length\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
/* 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)) {
|
||||||
|
printf("MSI_ENTRY cycle detected at level %d\n", cnt);
|
||||||
|
OPENSSL_free(entry);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dirent = (MSI_DIRENT *)OPENSSL_malloc(sizeof(MSI_DIRENT));
|
dirent = (MSI_DIRENT *)OPENSSL_malloc(sizeof(MSI_DIRENT));
|
||||||
memcpy(dirent->name, entry->name, entry->nameLen);
|
memcpy(dirent->name, entry->name, entry->nameLen);
|
||||||
dirent->nameLen = entry->nameLen;
|
dirent->nameLen = entry->nameLen;
|
||||||
dirent->type = entry->type;
|
dirent->type = entry->type;
|
||||||
dirent->entry = entry;
|
dirent->entry = entry;
|
||||||
dirent->children = sk_MSI_DIRENT_new_null();
|
dirent->children = sk_MSI_DIRENT_new_null();
|
||||||
|
dirent->next = NULL; /* fail-safe */
|
||||||
|
|
||||||
if (parent != NULL) {
|
/* Floyd's cycle-finding algorithm */
|
||||||
sk_MSI_DIRENT_push(parent->children, dirent);
|
if (!ret) { /* initialized (non-root entry) */
|
||||||
|
if (cnt++ & 1) /* move the tortoise every other invocation of msi_dirent_new() */
|
||||||
|
tortoise = tortoise->next;
|
||||||
|
hare->next = dirent; /* build a linked list of visited entries */
|
||||||
|
hare = dirent; /* move the hare every time */
|
||||||
|
} else { /* initialization needed (root entry) */
|
||||||
|
cnt = 0;
|
||||||
|
tortoise = dirent;
|
||||||
|
hare = dirent;
|
||||||
}
|
}
|
||||||
/* NOTE : These links are a tree, not a linked list */
|
|
||||||
msi_dirent_new(msi, get_entry(msi, entry->leftSiblingID), parent);
|
|
||||||
msi_dirent_new(msi, get_entry(msi, entry->rightSiblingID), parent);
|
|
||||||
|
|
||||||
if (entry->type != DIR_STREAM) {
|
if (parent && !sk_MSI_DIRENT_push(parent->children, dirent)) {
|
||||||
msi_dirent_new(msi, get_entry(msi, entry->childID), dirent);
|
printf("Failed to insert MSI_DIRENT\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
return dirent;
|
|
||||||
|
if (ret)
|
||||||
|
*ret = dirent;
|
||||||
|
|
||||||
|
if (!recurse_entry(msi, entry->leftSiblingID, parent)
|
||||||
|
|| !recurse_entry(msi, entry->rightSiblingID, parent)
|
||||||
|
|| !recurse_entry(msi, entry->childID, dirent)) {
|
||||||
|
printf("Failed to add a sibling or a child to the tree\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a sibling or a child to the tree */
|
||||||
|
/* NOTE: These links are a tree, not a linked list */
|
||||||
|
static int recurse_entry(MSI_FILE *msi, uint32_t entryID, MSI_DIRENT *parent)
|
||||||
|
{
|
||||||
|
MSI_ENTRY *node;
|
||||||
|
|
||||||
|
/* The special NOSTREAM (0xFFFFFFFF) value is used as a terminator */
|
||||||
|
if (entryID == NOSTREAM) /* stop condition */
|
||||||
|
return 1; /* OK */
|
||||||
|
|
||||||
|
node = get_entry(msi, entryID, FALSE);
|
||||||
|
if (!node) {
|
||||||
|
printf("Corrupted ID: 0x%08X\n", entryID);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!msi_dirent_new(msi, node, parent, NULL)) {
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return DigitalSignature and MsiDigitalSignatureEx */
|
/* Return DigitalSignature and MsiDigitalSignatureEx */
|
||||||
@ -456,7 +687,8 @@ int msi_hash_dir(MSI_FILE *msi, MSI_DIRENT *dirent, BIO *hash, int is_root)
|
|||||||
}
|
}
|
||||||
indata = (char *)OPENSSL_malloc(inlen);
|
indata = (char *)OPENSSL_malloc(inlen);
|
||||||
if (!msi_file_read(msi, child->entry, 0, indata, inlen)) {
|
if (!msi_file_read(msi, child->entry, 0, indata, inlen)) {
|
||||||
printf("Read stream data error\n\n");
|
printf("Failed to read stream data\n");
|
||||||
|
OPENSSL_free(indata);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
BIO_write(hash, indata, inlen);
|
BIO_write(hash, indata, inlen);
|
||||||
@ -464,6 +696,7 @@ int msi_hash_dir(MSI_FILE *msi, MSI_DIRENT *dirent, BIO *hash, int is_root)
|
|||||||
}
|
}
|
||||||
if (child->type == DIR_STORAGE) {
|
if (child->type == DIR_STORAGE) {
|
||||||
if (!msi_hash_dir(msi, child, hash, 0)) {
|
if (!msi_hash_dir(msi, child, hash, 0)) {
|
||||||
|
printf("Failed to hash a MSI storage\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -476,15 +709,19 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Compute a simple sha1/sha256 message digest of the MSI file */
|
/* Compute a simple sha1/sha256 message digest of the MSI file */
|
||||||
void msi_calc_digest(char *indata, const EVP_MD *md, u_char *mdbuf, size_t fileend)
|
int msi_calc_digest(char *indata, const EVP_MD *md, u_char *mdbuf, uint32_t fileend)
|
||||||
{
|
{
|
||||||
BIO *bio = NULL;
|
BIO *bio = NULL;
|
||||||
EVP_MD_CTX *mdctx;
|
EVP_MD_CTX *mdctx;
|
||||||
size_t n;
|
uint32_t n;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
bio = BIO_new_mem_buf(indata, fileend);
|
bio = BIO_new_mem_buf(indata, fileend);
|
||||||
mdctx = EVP_MD_CTX_new();
|
mdctx = EVP_MD_CTX_new();
|
||||||
EVP_DigestInit(mdctx, md);
|
if (!EVP_DigestInit(mdctx, md)) {
|
||||||
|
printf("Unable to set up the digest context\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
memset(mdbuf, 0, EVP_MAX_MD_SIZE);
|
memset(mdbuf, 0, EVP_MAX_MD_SIZE);
|
||||||
(void)BIO_seek(bio, 0);
|
(void)BIO_seek(bio, 0);
|
||||||
|
|
||||||
@ -492,7 +729,7 @@ void msi_calc_digest(char *indata, const EVP_MD *md, u_char *mdbuf, size_t filee
|
|||||||
while (n < fileend) {
|
while (n < fileend) {
|
||||||
int l;
|
int l;
|
||||||
static u_char bfb[16*1024*1024];
|
static u_char bfb[16*1024*1024];
|
||||||
size_t want = fileend - n;
|
uint32_t want = fileend - n;
|
||||||
if (want > sizeof bfb)
|
if (want > sizeof bfb)
|
||||||
want = sizeof bfb;
|
want = sizeof bfb;
|
||||||
l = BIO_read(bio, bfb, want);
|
l = BIO_read(bio, bfb, want);
|
||||||
@ -502,13 +739,16 @@ void msi_calc_digest(char *indata, const EVP_MD *md, u_char *mdbuf, size_t filee
|
|||||||
n += l;
|
n += l;
|
||||||
}
|
}
|
||||||
EVP_DigestFinal(mdctx, mdbuf, NULL);
|
EVP_DigestFinal(mdctx, mdbuf, NULL);
|
||||||
|
ret = 1; /* OK */
|
||||||
|
out:
|
||||||
EVP_MD_CTX_free(mdctx);
|
EVP_MD_CTX_free(mdctx);
|
||||||
BIO_free(bio);
|
BIO_free(bio);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ministream_append(MSI_OUT *out, char *buf, int len)
|
static void ministream_append(MSI_OUT *out, char *buf, int len)
|
||||||
{
|
{
|
||||||
int needSectors = (len + out->sectorSize - 1) / out->sectorSize;
|
uint32_t needSectors = (len + out->sectorSize - 1) / out->sectorSize;
|
||||||
if (out->miniStreamLen + len >= out->ministreamsMemallocCount * out->sectorSize) {
|
if (out->miniStreamLen + len >= out->ministreamsMemallocCount * out->sectorSize) {
|
||||||
out->ministreamsMemallocCount += needSectors;
|
out->ministreamsMemallocCount += needSectors;
|
||||||
out->ministream = OPENSSL_realloc(out->ministream, out->ministreamsMemallocCount * out->sectorSize);
|
out->ministream = OPENSSL_realloc(out->ministream, out->ministreamsMemallocCount * out->sectorSize);
|
||||||
@ -626,7 +866,7 @@ static int stream_read(MSI_FILE *msi, MSI_ENTRY *entry, u_char *p_msi, int len_m
|
|||||||
inlen = len_msiex;
|
inlen = len_msiex;
|
||||||
} else {
|
} else {
|
||||||
if (!msi_file_read(msi, entry, 0, *indata, inlen)) {
|
if (!msi_file_read(msi, entry, 0, *indata, inlen)) {
|
||||||
printf("Read stream data error\n");
|
printf("Failed to read stream data\n");
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -680,7 +920,7 @@ static int stream_handle(MSI_FILE *msi, MSI_DIRENT *dirent, u_char *p_msi, int l
|
|||||||
out->miniSectorNum += 1;
|
out->miniSectorNum += 1;
|
||||||
PUT_UINT32_LE(out->miniSectorNum, buf);
|
PUT_UINT32_LE(out->miniSectorNum, buf);
|
||||||
minifat_append(out, buf, 4);
|
minifat_append(out, buf, 4);
|
||||||
inlen -= msi->m_minisectorSize;
|
inlen -= (uint32_t)msi->m_minisectorSize;
|
||||||
}
|
}
|
||||||
PUT_UINT32_LE(ENDOFCHAIN, buf);
|
PUT_UINT32_LE(ENDOFCHAIN, buf);
|
||||||
minifat_append(out, buf, 4);
|
minifat_append(out, buf, 4);
|
||||||
@ -701,7 +941,7 @@ static int stream_handle(MSI_FILE *msi, MSI_DIRENT *dirent, u_char *p_msi, int l
|
|||||||
out->sectorNum += 1;
|
out->sectorNum += 1;
|
||||||
PUT_UINT32_LE(out->sectorNum, buf);
|
PUT_UINT32_LE(out->sectorNum, buf);
|
||||||
fat_append(out, buf, 4);
|
fat_append(out, buf, 4);
|
||||||
inlen -= out->sectorSize;
|
inlen -= (uint32_t)out->sectorSize;
|
||||||
}
|
}
|
||||||
PUT_UINT32_LE(ENDOFCHAIN, buf);
|
PUT_UINT32_LE(ENDOFCHAIN, buf);
|
||||||
fat_append(out, buf, 4);
|
fat_append(out, buf, 4);
|
||||||
@ -856,15 +1096,15 @@ static int dirents_save(MSI_DIRENT *dirent, BIO *outdata, MSI_OUT *out, int *str
|
|||||||
out->dirtreeLen += DIRENT_SIZE;
|
out->dirtreeLen += DIRENT_SIZE;
|
||||||
for (i = 0; i < childenNum; i++) {
|
for (i = 0; i < childenNum; i++) {
|
||||||
MSI_DIRENT *child = sk_MSI_DIRENT_value(children, i);
|
MSI_DIRENT *child = sk_MSI_DIRENT_value(children, i);
|
||||||
int last = i == childenNum - 1 ? 1 : 0;
|
int last_dir = i == childenNum - 1 ? 1 : 0;
|
||||||
*streamId += 1;
|
*streamId += 1;
|
||||||
if (child->type == DIR_STORAGE) {
|
if (child->type == DIR_STORAGE) {
|
||||||
count += dirents_save(child, outdata, out, streamId, count, last);
|
count += dirents_save(child, outdata, out, streamId, count, last_dir);
|
||||||
} else { /* DIR_STREAM */
|
} else { /* DIR_STREAM */
|
||||||
count = 0;
|
count = 0;
|
||||||
child->entry->colorFlag = BLACK_COLOR;
|
child->entry->colorFlag = BLACK_COLOR;
|
||||||
child->entry->leftSiblingID = NOSTREAM;
|
child->entry->leftSiblingID = NOSTREAM;
|
||||||
if (last) {
|
if (last_dir) {
|
||||||
child->entry->rightSiblingID = NOSTREAM;
|
child->entry->rightSiblingID = NOSTREAM;
|
||||||
} else {
|
} else {
|
||||||
child->entry->rightSiblingID = *streamId + 1;
|
child->entry->rightSiblingID = *streamId + 1;
|
||||||
@ -1035,7 +1275,6 @@ static char *header_new(MSI_FILE_HDR *hdr, MSI_OUT *out)
|
|||||||
|
|
||||||
static int msiout_set(MSI_FILE *msi, int len_msi, int len_msiex, MSI_OUT *out)
|
static int msiout_set(MSI_FILE *msi, int len_msi, int len_msiex, MSI_OUT *out)
|
||||||
{
|
{
|
||||||
MSI_FILE_HDR *hdr = msi_header_get(msi);
|
|
||||||
int msi_size, msiex_size;
|
int msi_size, msiex_size;
|
||||||
|
|
||||||
out->sectorSize = msi->m_sectorSize;
|
out->sectorSize = msi->m_sectorSize;
|
||||||
@ -1057,9 +1296,9 @@ static int msiout_set(MSI_FILE *msi, int len_msi, int len_msiex, MSI_OUT *out)
|
|||||||
printf("DIFAT sectors are not supported\n");
|
printf("DIFAT sectors are not supported\n");
|
||||||
return 0;/* FAILED */
|
return 0;/* FAILED */
|
||||||
}
|
}
|
||||||
out->header = header_new(hdr, out);
|
out->header = header_new(msi->m_hdr, out);
|
||||||
out->minifatMemallocCount = hdr->numMiniFATSector;
|
out->minifatMemallocCount = msi->m_hdr->numMiniFATSector;
|
||||||
out->fatMemallocCount = hdr->numFATSector;
|
out->fatMemallocCount = msi->m_hdr->numFATSector;
|
||||||
out->ministream = NULL;
|
out->ministream = NULL;
|
||||||
out->minifat = OPENSSL_malloc(out->minifatMemallocCount * out->sectorSize);
|
out->minifat = OPENSSL_malloc(out->minifatMemallocCount * out->sectorSize);
|
||||||
out->fat = OPENSSL_malloc(out->fatMemallocCount * out->sectorSize);
|
out->fat = OPENSSL_malloc(out->fatMemallocCount * out->sectorSize);
|
||||||
@ -1097,3 +1336,13 @@ out:
|
|||||||
OPENSSL_free(out.minifat);
|
OPENSSL_free(out.minifat);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Local Variables:
|
||||||
|
c-basic-offset: 4
|
||||||
|
tab-width: 4
|
||||||
|
indent-tabs-mode: t
|
||||||
|
End:
|
||||||
|
|
||||||
|
vim: set ts=4 noexpandtab:
|
||||||
|
*/
|
||||||
|
59
msi.h
59
msi.h
@ -74,9 +74,9 @@
|
|||||||
|
|
||||||
#define GET_UINT8_LE(p) ((u_char*)(p))[0]
|
#define GET_UINT8_LE(p) ((u_char*)(p))[0]
|
||||||
|
|
||||||
#define GET_UINT16_LE(p) (((u_char*)(p))[0] | (((u_char*)(p))[1]<<8))
|
#define GET_UINT16_LE(p) (uint16_t)(((u_char*)(p))[0] | (((u_char*)(p))[1]<<8))
|
||||||
|
|
||||||
#define GET_UINT32_LE(p) (((u_char*)(p))[0] | (((u_char*)(p))[1]<<8) | \
|
#define GET_UINT32_LE(p) (uint32_t)(((u_char*)(p))[0] | (((u_char*)(p))[1]<<8) | \
|
||||||
(((u_char*)(p))[2]<<16) | (((u_char*)(p))[3]<<24))
|
(((u_char*)(p))[2]<<16) | (((u_char*)(p))[3]<<24))
|
||||||
|
|
||||||
#define PUT_UINT8_LE(i,p) \
|
#define PUT_UINT8_LE(i,p) \
|
||||||
@ -92,6 +92,17 @@
|
|||||||
((u_char*)(p))[2] = ((i)>>16) & 0xff; \
|
((u_char*)(p))[2] = ((i)>>16) & 0xff; \
|
||||||
((u_char*)(p))[3] = ((i)>>24) & 0xff
|
((u_char*)(p))[3] = ((i)>>24) & 0xff
|
||||||
|
|
||||||
|
#ifndef FALSE
|
||||||
|
#define FALSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TRUE
|
||||||
|
#define TRUE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SIZE_64K 65536 /* 2^16 */
|
||||||
|
#define SIZE_16M 16777216 /* 2^24 */
|
||||||
|
|
||||||
typedef unsigned char u_char;
|
typedef unsigned char u_char;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -131,23 +142,24 @@ typedef struct {
|
|||||||
u_char size[8];
|
u_char size[8];
|
||||||
} MSI_ENTRY;
|
} MSI_ENTRY;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct msi_dirent_struct {
|
||||||
u_char name[DIRENT_MAX_NAME_SIZE];
|
u_char name[DIRENT_MAX_NAME_SIZE];
|
||||||
uint16_t nameLen;
|
uint16_t nameLen;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
MSI_ENTRY *entry;
|
MSI_ENTRY *entry;
|
||||||
STACK_OF(MSI_DIRENT) *children;
|
STACK_OF(MSI_DIRENT) *children;
|
||||||
|
struct msi_dirent_struct *next; /* for cycle detection */
|
||||||
} MSI_DIRENT;
|
} MSI_DIRENT;
|
||||||
|
|
||||||
DEFINE_STACK_OF(MSI_DIRENT)
|
DEFINE_STACK_OF(MSI_DIRENT)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const u_char *m_buffer;
|
const u_char *m_buffer;
|
||||||
size_t m_bufferLen;
|
uint32_t m_bufferLen;
|
||||||
MSI_FILE_HDR *m_hdr;
|
MSI_FILE_HDR *m_hdr;
|
||||||
size_t m_sectorSize;
|
uint32_t m_sectorSize;
|
||||||
size_t m_minisectorSize;
|
uint32_t m_minisectorSize;
|
||||||
size_t m_miniStreamStartSector;
|
uint32_t m_miniStreamStartSector;
|
||||||
} MSI_FILE;
|
} MSI_FILE;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -167,10 +179,10 @@ typedef struct {
|
|||||||
int fatSectorsCount;
|
int fatSectorsCount;
|
||||||
int miniSectorNum;
|
int miniSectorNum;
|
||||||
int sectorNum;
|
int sectorNum;
|
||||||
size_t sectorSize;
|
uint32_t sectorSize;
|
||||||
} MSI_OUT;
|
} MSI_OUT;
|
||||||
|
|
||||||
static u_char msi_magic[] = {
|
static const u_char msi_magic[] = {
|
||||||
0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1
|
0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -191,16 +203,35 @@ static const u_char digital_signature_ex[] = {
|
|||||||
0x45, 0x00, 0x78, 0x00, 0x00, 0x00
|
0x45, 0x00, 0x78, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
int msi_file_read(MSI_FILE *msi, MSI_ENTRY *entry, size_t offset, char *buffer, size_t len);
|
static const u_char msi_root_entry[] = {
|
||||||
MSI_FILE *msi_file_new(char *buffer, size_t len);
|
0x52, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x74, 0x00,
|
||||||
|
0x20, 0x00, 0x45, 0x00, 0x6E, 0x00, 0x74, 0x00,
|
||||||
|
0x72, 0x00, 0x79, 0x00, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u_char msi_zeroes[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
int msi_file_read(MSI_FILE *msi, MSI_ENTRY *entry, uint32_t offset, char *buffer, uint32_t len);
|
||||||
|
MSI_FILE *msi_file_new(char *buffer, uint32_t len);
|
||||||
void msi_file_free(MSI_FILE *msi);
|
void msi_file_free(MSI_FILE *msi);
|
||||||
MSI_ENTRY *msi_root_entry_get(MSI_FILE *msi);
|
MSI_ENTRY *msi_root_entry_get(MSI_FILE *msi);
|
||||||
MSI_DIRENT *msi_dirent_new(MSI_FILE *msi, MSI_ENTRY *entry, MSI_DIRENT *parent);
|
int msi_dirent_new(MSI_FILE *msi, MSI_ENTRY *entry, MSI_DIRENT *parent, MSI_DIRENT **ret);
|
||||||
MSI_ENTRY *msi_signatures_get(MSI_DIRENT *dirent, MSI_ENTRY **dse);
|
MSI_ENTRY *msi_signatures_get(MSI_DIRENT *dirent, MSI_ENTRY **dse);
|
||||||
void msi_dirent_free(MSI_DIRENT *dirent);
|
void msi_dirent_free(MSI_DIRENT *dirent);
|
||||||
MSI_FILE_HDR *msi_header_get(MSI_FILE *msi);
|
|
||||||
int msi_prehash_dir(MSI_DIRENT *dirent, BIO *hash, int is_root);
|
int msi_prehash_dir(MSI_DIRENT *dirent, BIO *hash, int is_root);
|
||||||
int msi_hash_dir(MSI_FILE *msi, MSI_DIRENT *dirent, BIO *hash, int is_root);
|
int msi_hash_dir(MSI_FILE *msi, MSI_DIRENT *dirent, BIO *hash, int is_root);
|
||||||
void msi_calc_digest(char *indata, const EVP_MD *md, u_char *mdbuf, size_t fileend);
|
int msi_calc_digest(char *indata, const EVP_MD *md, u_char *mdbuf, uint32_t fileend);
|
||||||
int msi_dirent_delete(MSI_DIRENT *dirent, const u_char *name, uint16_t nameLen);
|
int msi_dirent_delete(MSI_DIRENT *dirent, const u_char *name, uint16_t nameLen);
|
||||||
int msi_file_write(MSI_FILE *msi, MSI_DIRENT *dirent, u_char *p, int len, u_char *p_msiex, int len_msiex, BIO *outdata);
|
int msi_file_write(MSI_FILE *msi, MSI_DIRENT *dirent, u_char *p, int len, u_char *p_msiex, int len_msiex, BIO *outdata);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Local Variables:
|
||||||
|
c-basic-offset: 4
|
||||||
|
tab-width: 4
|
||||||
|
indent-tabs-mode: t
|
||||||
|
End:
|
||||||
|
|
||||||
|
vim: set ts=4 noexpandtab:
|
||||||
|
*/
|
||||||
|
76
osslsigncode.bash
Normal file
76
osslsigncode.bash
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# bash completion for osslsigncode -*- shell-script -*-
|
||||||
|
# Copyright (C) 2021-2022 Michał Trojnara <Michal.Trojnara@stunnel.org>
|
||||||
|
# Author: Małgorzata Olszówka <Malgorzata.Olszowka@stunnel.org>
|
||||||
|
|
||||||
|
bind 'set show-all-if-ambiguous on'
|
||||||
|
bind 'set completion-ignore-case on'
|
||||||
|
COMP_WORDBREAKS=${COMP_WORDBREAKS//:}
|
||||||
|
|
||||||
|
_comp_cmd_osslsigncode()
|
||||||
|
{
|
||||||
|
local cur prev words cword
|
||||||
|
_init_completion || return
|
||||||
|
|
||||||
|
local commands command options timestamps rfc3161
|
||||||
|
|
||||||
|
commands="--help --version -v
|
||||||
|
sign add attach-signature extract-signature remove-signature verify"
|
||||||
|
|
||||||
|
timestamps="http://timestamp.digicert.com
|
||||||
|
http://time.certum.pl
|
||||||
|
http://timestamp.sectigo.com
|
||||||
|
http://timestamp.globalsign.com/?signature=sha2"
|
||||||
|
|
||||||
|
rfc3161="http://timestamp.digicert.com
|
||||||
|
http://time.certum.pl
|
||||||
|
http://timestamp.entrust.net/TSS/RFC3161sha2TS
|
||||||
|
http://tss.accv.es:8318/tsa
|
||||||
|
http://kstamp.keynectis.com/KSign/
|
||||||
|
http://sha256timestamp.ws.symantec.com/sha256/timestamp"
|
||||||
|
|
||||||
|
|
||||||
|
if ((cword == 1)); then
|
||||||
|
COMPREPLY=($(compgen -W "${commands}" -- ${cur}))
|
||||||
|
else
|
||||||
|
command=${words[1]}
|
||||||
|
case $prev in
|
||||||
|
-ac | -c | -catalog | -certs | -spc | -key | -pkcs12 | -pass | \
|
||||||
|
-readpass | -pkcs11engine | -pkcs11module | -in | -out | -sigin | \
|
||||||
|
-n | -CAfile | -CRLfile | -TSA-CAfile | -TSA-CRLfile)
|
||||||
|
_filedir
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
-h | -require-leaf-hash)
|
||||||
|
COMPREPLY=($(compgen -W 'md5 sha1 sha2 sha256 sha384 sha512' \
|
||||||
|
-- "$cur"))
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
-jp)
|
||||||
|
COMPREPLY=($(compgen -W 'low medium high' -- "$cur"))
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
-t)
|
||||||
|
COMPREPLY=($(compgen -W "${timestamps}" -- "$cur"))
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
-ts)
|
||||||
|
COMPREPLY=($(compgen -W "${rfc3161}" -- "$cur"))
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
-i | -p)
|
||||||
|
_known_hosts_real -- "$cur"
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
# possible options for the command
|
||||||
|
options=$(_parse_help "$1" "$command --help" 2>/dev/null)
|
||||||
|
COMPREPLY=($(compgen -W "${options}" -- ${cur}))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
} &&
|
||||||
|
complete -F _comp_cmd_osslsigncode osslsigncode
|
||||||
|
|
||||||
|
# ex: filetype=sh
|
902
osslsigncode.c
902
osslsigncode.c
File diff suppressed because it is too large
Load Diff
@ -21,162 +21,178 @@ make_certs() {
|
|||||||
|
|
||||||
# OpenSSL settings
|
# OpenSSL settings
|
||||||
CONF="${script_path}/openssl_intermediate.cnf"
|
CONF="${script_path}/openssl_intermediate.cnf"
|
||||||
TEMP_LD_LIBRARY_PATH=$LD_LIBRARY_PATH
|
|
||||||
if test -n "$1"
|
if test -n "$1"
|
||||||
then
|
then
|
||||||
OPENSSL="$1/bin/openssl"
|
OPENSSL="$1/bin/openssl"
|
||||||
LD_LIBRARY_PATH="$1/lib"
|
export LD_LIBRARY_PATH="$1/lib:$1/lib64"
|
||||||
else
|
else
|
||||||
OPENSSL=openssl
|
OPENSSL=openssl
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir "demoCA/" 2>> "makecerts.log" 1>&2
|
mkdir "demoCA/" 2>> "makecerts.log" 1>&2
|
||||||
touch "demoCA/index.txt"
|
touch "demoCA/index.txt"
|
||||||
touch "demoCA/index.txt.attr"
|
echo -n "unique_subject = no" > "demoCA/index.txt.attr"
|
||||||
echo 1000 > "demoCA/serial"
|
echo 1000 > "demoCA/serial"
|
||||||
date > "makecerts.log"
|
date > "makecerts.log"
|
||||||
$OPENSSL version 2>> "makecerts.log" 1>&2
|
"$OPENSSL" version 2>> "makecerts.log" 1>&2
|
||||||
echo -n "$password" > "password.txt"
|
echo -n "$password" > "password.txt"
|
||||||
|
|
||||||
printf "\nGenerate root CA certificate\n" >> "makecerts.log"
|
printf "\nGenerate root CA certificate\n" >> "makecerts.log"
|
||||||
$OPENSSL genrsa -out demoCA/CA.key \
|
"$OPENSSL" genrsa -out demoCA/CA.key \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
|
test_result $?
|
||||||
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
|
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
|
||||||
script_path=$(pwd)
|
script_path=$(pwd)
|
||||||
OPENSSL=openssl
|
OPENSSL="$0"
|
||||||
|
export LD_LIBRARY_PATH="$1"
|
||||||
CONF="${script_path}/openssl_root.cnf"
|
CONF="${script_path}/openssl_root.cnf"
|
||||||
$OPENSSL req -config $CONF -new -x509 -days 3600 -key demoCA/CA.key -out tmp/CACert.pem \
|
"$OPENSSL" req -config "$CONF" -new -x509 -days 3600 -key demoCA/CA.key -out tmp/CACert.pem \
|
||||||
-subj "/C=PL/O=osslsigncode/OU=Certification Authority/CN=Root CA" \
|
-subj "/C=PL/O=osslsigncode/OU=Certification Authority/CN=Root CA" \
|
||||||
2>> "makecerts.log" 1>&2'
|
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
|
||||||
test_result $?
|
test_result $?
|
||||||
|
|
||||||
printf "\nGenerate intermediate CA certificate\n" >> "makecerts.log"
|
printf "\nGenerate intermediate CA certificate\n" >> "makecerts.log"
|
||||||
$OPENSSL genrsa -out demoCA/intermediate.key \
|
"$OPENSSL" genrsa -out demoCA/intermediate.key \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
|
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
|
||||||
script_path=$(pwd)
|
script_path=$(pwd)
|
||||||
OPENSSL=openssl
|
OPENSSL="$0"
|
||||||
|
export LD_LIBRARY_PATH="$1"
|
||||||
CONF="${script_path}/openssl_intermediate.cnf"
|
CONF="${script_path}/openssl_intermediate.cnf"
|
||||||
$OPENSSL req -config $CONF -new -key demoCA/intermediate.key -out demoCA/intermediate.csr \
|
"$OPENSSL" req -config "$CONF" -new -key demoCA/intermediate.key -out demoCA/intermediate.csr \
|
||||||
-subj "/C=PL/O=osslsigncode/OU=Certification Authority/CN=Intermediate CA" \
|
-subj "/C=PL/O=osslsigncode/OU=Certification Authority/CN=Intermediate CA" \
|
||||||
2>> "makecerts.log" 1>&2'
|
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
|
||||||
test_result $?
|
test_result $?
|
||||||
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
|
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
|
||||||
script_path=$(pwd)
|
script_path=$(pwd)
|
||||||
OPENSSL=openssl
|
OPENSSL="$0"
|
||||||
|
export LD_LIBRARY_PATH="$1"
|
||||||
CONF="${script_path}/openssl_root.cnf"
|
CONF="${script_path}/openssl_root.cnf"
|
||||||
$OPENSSL ca -config $CONF -batch -in demoCA/intermediate.csr -out demoCA/intermediate.cer \
|
"$OPENSSL" ca -config "$CONF" -batch -in demoCA/intermediate.csr -out demoCA/intermediate.cer \
|
||||||
2>> "makecerts.log" 1>&2'
|
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
|
||||||
test_result $?
|
test_result $?
|
||||||
$OPENSSL x509 -in demoCA/intermediate.cer -out tmp/intermediate.pem \
|
"$OPENSSL" x509 -in demoCA/intermediate.cer -out tmp/intermediate.pem \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
|
test_result $?
|
||||||
|
|
||||||
printf "\nGenerate private RSA encrypted key\n" >> "makecerts.log"
|
printf "\nGenerate private RSA encrypted key\n" >> "makecerts.log"
|
||||||
$OPENSSL genrsa -des3 -out demoCA/private.key -passout pass:$password \
|
"$OPENSSL" genrsa -des3 -out demoCA/private.key -passout pass:"$password" \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
test_result $?
|
test_result $?
|
||||||
cat demoCA/private.key >> tmp/keyp.pem 2>> "makecerts.log"
|
cat demoCA/private.key >> tmp/keyp.pem 2>> "makecerts.log"
|
||||||
|
test_result $?
|
||||||
|
|
||||||
printf "\nGenerate private RSA decrypted key\n" >> "makecerts.log"
|
printf "\nGenerate private RSA decrypted key\n" >> "makecerts.log"
|
||||||
$OPENSSL rsa -in demoCA/private.key -passin pass:$password -out tmp/key.pem \
|
"$OPENSSL" rsa -in demoCA/private.key -passin pass:"$password" -out tmp/key.pem \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
test_result $?
|
test_result $?
|
||||||
|
|
||||||
printf "\nGenerate a certificate to revoke\n" >> "makecerts.log"
|
printf "\nGenerate a certificate to revoke\n" >> "makecerts.log"
|
||||||
$OPENSSL req -config $CONF -new -key demoCA/private.key -passin pass:$password -out demoCA/revoked.csr \
|
"$OPENSSL" req -config "$CONF" -new -key demoCA/private.key -passin pass:"$password" -out demoCA/revoked.csr \
|
||||||
-subj "/C=PL/O=osslsigncode/OU=CSP/CN=Revoked/emailAddress=osslsigncode@example.com" \
|
-subj "/C=PL/O=osslsigncode/OU=CSP/CN=Revoked/emailAddress=osslsigncode@example.com" \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
$OPENSSL ca -config $CONF -batch -in demoCA/revoked.csr -out demoCA/revoked.cer \
|
test_result $?
|
||||||
|
"$OPENSSL" ca -config "$CONF" -batch -in demoCA/revoked.csr -out demoCA/revoked.cer \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
$OPENSSL x509 -in demoCA/revoked.cer -out tmp/revoked.pem \
|
test_result $?
|
||||||
|
"$OPENSSL" x509 -in demoCA/revoked.cer -out tmp/revoked.pem \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
|
test_result $?
|
||||||
|
|
||||||
printf "\nRevoke above certificate\n" >> "makecerts.log"
|
printf "\nRevoke above certificate\n" >> "makecerts.log"
|
||||||
$OPENSSL ca -config $CONF -revoke demoCA/1001.pem \
|
"$OPENSSL" ca -config "$CONF" -revoke demoCA/revoked.cer \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
|
test_result $?
|
||||||
|
|
||||||
printf "\nAttach intermediate certificate to revoked certificate\n" >> "makecerts.log"
|
printf "\nAttach intermediate certificate to revoked certificate\n" >> "makecerts.log"
|
||||||
cat tmp/intermediate.pem >> tmp/revoked.pem
|
cat tmp/intermediate.pem >> tmp/revoked.pem 2>> "makecerts.log"
|
||||||
|
test_result $?
|
||||||
|
|
||||||
printf "\nGenerate CRL file\n" >> "makecerts.log"
|
printf "\nGenerate CRL file\n" >> "makecerts.log"
|
||||||
TZ=GMT faketime -f '@2019-01-01 00:00:00' /bin/bash -c '
|
TZ=GMT faketime -f '@2019-01-01 00:00:00' /bin/bash -c '
|
||||||
script_path=$(pwd)
|
script_path=$(pwd)
|
||||||
OPENSSL=openssl
|
OPENSSL="$0"
|
||||||
|
export LD_LIBRARY_PATH="$1"
|
||||||
CONF="${script_path}/openssl_intermediate.cnf"
|
CONF="${script_path}/openssl_intermediate.cnf"
|
||||||
$OPENSSL ca -config $CONF -gencrl -crldays 8766 -out tmp/CACertCRL.pem \
|
"$OPENSSL" ca -config "$CONF" -gencrl -crldays 8766 -out tmp/CACertCRL.pem \
|
||||||
2>> "makecerts.log" 1>&2'
|
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
|
||||||
|
test_result $?
|
||||||
|
|
||||||
printf "\nConvert revoked certificate to SPC format\n" >> "makecerts.log"
|
printf "\nConvert revoked certificate to SPC format\n" >> "makecerts.log"
|
||||||
$OPENSSL crl2pkcs7 -in tmp/CACertCRL.pem -certfile tmp/revoked.pem -outform DER -out tmp/revoked.spc \
|
"$OPENSSL" crl2pkcs7 -in tmp/CACertCRL.pem -certfile tmp/revoked.pem -outform DER -out tmp/revoked.spc \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
test_result $?
|
test_result $?
|
||||||
|
|
||||||
printf "\nGenerate CSP Cross-Certificate\n" >> "makecerts.log"
|
printf "\nGenerate CSP Cross-Certificate\n" >> "makecerts.log"
|
||||||
$OPENSSL genrsa -out demoCA/cross.key \
|
"$OPENSSL" genrsa -out demoCA/cross.key \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
TZ=GMT faketime -f '@2018-01-01 00:00:00' /bin/bash -c '
|
TZ=GMT faketime -f '@2018-01-01 00:00:00' /bin/bash -c '
|
||||||
script_path=$(pwd)
|
script_path=$(pwd)
|
||||||
OPENSSL=openssl
|
OPENSSL="$0"
|
||||||
|
export LD_LIBRARY_PATH="$1"
|
||||||
CONF="${script_path}/openssl_intermediate.cnf"
|
CONF="${script_path}/openssl_intermediate.cnf"
|
||||||
$OPENSSL req -config $CONF -new -x509 -days 900 -key demoCA/cross.key -out tmp/crosscert.pem \
|
"$OPENSSL" req -config "$CONF" -new -x509 -days 900 -key demoCA/cross.key -out tmp/crosscert.pem \
|
||||||
-subj "/C=PL/O=osslsigncode/OU=CSP/CN=crosscert/emailAddress=osslsigncode@example.com" \
|
-subj "/C=PL/O=osslsigncode/OU=CSP/CN=crosscert/emailAddress=osslsigncode@example.com" \
|
||||||
2>> "makecerts.log" 1>&2'
|
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
|
||||||
test_result $?
|
test_result $?
|
||||||
|
|
||||||
printf "\nGenerate code signing certificate\n" >> "makecerts.log"
|
printf "\nGenerate code signing certificate\n" >> "makecerts.log"
|
||||||
$OPENSSL req -config $CONF -new -key demoCA/private.key -passin pass:$password -out demoCA/cert.csr \
|
"$OPENSSL" req -config "$CONF" -new -key demoCA/private.key -passin pass:"$password" -out demoCA/cert.csr \
|
||||||
-subj "/C=PL/ST=Mazovia Province/L=Warsaw/O=osslsigncode/OU=CSP/CN=Certificate/emailAddress=osslsigncode@example.com" \
|
-subj "/C=PL/ST=Mazovia Province/L=Warsaw/O=osslsigncode/OU=CSP/CN=Certificate/emailAddress=osslsigncode@example.com" \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
test_result $?
|
test_result $?
|
||||||
$OPENSSL ca -config $CONF -batch -in demoCA/cert.csr -out demoCA/cert.cer \
|
"$OPENSSL" ca -config "$CONF" -batch -in demoCA/cert.csr -out demoCA/cert.cer \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
test_result $?
|
test_result $?
|
||||||
$OPENSSL x509 -in demoCA/cert.cer -out tmp/cert.pem \
|
"$OPENSSL" x509 -in demoCA/cert.cer -out tmp/cert.pem \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
test_result $?
|
test_result $?
|
||||||
|
|
||||||
printf "\nConvert the key to DER format\n" >> "makecerts.log"
|
printf "\nConvert the key to DER format\n" >> "makecerts.log"
|
||||||
$OPENSSL rsa -in tmp/key.pem -outform DER -out tmp/key.der -passout pass:$password \
|
"$OPENSSL" rsa -in tmp/key.pem -outform DER -out tmp/key.der -passout pass:"$password" \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
test_result $?
|
test_result $?
|
||||||
|
|
||||||
printf "\nConvert the key to PVK format\n" >> "makecerts.log"
|
printf "\nConvert the key to PVK format\n" >> "makecerts.log"
|
||||||
$OPENSSL rsa -in tmp/key.pem -outform PVK -out tmp/key.pvk -pvk-none \
|
"$OPENSSL" rsa -in tmp/key.pem -outform PVK -out tmp/key.pvk -pvk-none \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
test_result $?
|
test_result $?
|
||||||
|
|
||||||
printf "\nConvert the certificate to DER format\n" >> "makecerts.log"
|
printf "\nConvert the certificate to DER format\n" >> "makecerts.log"
|
||||||
$OPENSSL x509 -in tmp/cert.pem -outform DER -out tmp/cert.der \
|
"$OPENSSL" x509 -in tmp/cert.pem -outform DER -out tmp/cert.der \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
test_result $?
|
test_result $?
|
||||||
|
|
||||||
printf "\nAttach intermediate certificate to code signing certificate\n" >> "makecerts.log"
|
printf "\nAttach intermediate certificate to code signing certificate\n" >> "makecerts.log"
|
||||||
cat tmp/intermediate.pem >> tmp/cert.pem
|
cat tmp/intermediate.pem >> tmp/cert.pem 2>> "makecerts.log"
|
||||||
|
test_result $?
|
||||||
|
|
||||||
printf "\nConvert the certificate to SPC format\n" >> "makecerts.log"
|
printf "\nConvert the certificate to SPC format\n" >> "makecerts.log"
|
||||||
$OPENSSL crl2pkcs7 -nocrl -certfile tmp/cert.pem -outform DER -out tmp/cert.spc \
|
"$OPENSSL" crl2pkcs7 -nocrl -certfile tmp/cert.pem -outform DER -out tmp/cert.spc \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
test_result $?
|
test_result $?
|
||||||
|
|
||||||
printf "\nConvert the certificate and the key into a PKCS#12 container\n" >> "makecerts.log"
|
printf "\nConvert the certificate and the key into a PKCS#12 container\n" >> "makecerts.log"
|
||||||
$OPENSSL pkcs12 -export -in tmp/cert.pem -inkey tmp/key.pem -out tmp/cert.p12 -passout pass:$password \
|
"$OPENSSL" pkcs12 -export -in tmp/cert.pem -inkey tmp/key.pem -out tmp/cert.p12 -passout pass:"$password" \
|
||||||
|
-keypbe aes-256-cbc -certpbe aes-256-cbc \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
test_result $?
|
test_result $?
|
||||||
|
|
||||||
printf "\nGenerate expired certificate\n" >> "makecerts.log"
|
printf "\nGenerate expired certificate\n" >> "makecerts.log"
|
||||||
$OPENSSL req -config $CONF -new -key demoCA/private.key -passin pass:$password -out demoCA/expired.csr \
|
"$OPENSSL" req -config "$CONF" -new -key demoCA/private.key -passin pass:"$password" -out demoCA/expired.csr \
|
||||||
-subj "/C=PL/ST=Mazovia Province/L=Warsaw/O=osslsigncode/OU=CSP/CN=Expired/emailAddress=osslsigncode@example.com" \
|
-subj "/C=PL/ST=Mazovia Province/L=Warsaw/O=osslsigncode/OU=CSP/CN=Expired/emailAddress=osslsigncode@example.com" \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
test_result $?
|
test_result $?
|
||||||
$OPENSSL ca -config $CONF -enddate "190101000000Z" -batch -in demoCA/expired.csr -out demoCA/expired.cer \
|
"$OPENSSL" ca -config "$CONF" -enddate "190101000000Z" -batch -in demoCA/expired.csr -out demoCA/expired.cer \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
test_result $?
|
test_result $?
|
||||||
$OPENSSL x509 -in demoCA/expired.cer -out tmp/expired.pem \
|
"$OPENSSL" x509 -in demoCA/expired.cer -out tmp/expired.pem \
|
||||||
2>> "makecerts.log" 1>&2
|
2>> "makecerts.log" 1>&2
|
||||||
test_result $?
|
test_result $?
|
||||||
|
|
||||||
printf "\nAttach intermediate certificate to expired certificate\n" >> "makecerts.log"
|
printf "\nAttach intermediate certificate to expired certificate\n" >> "makecerts.log"
|
||||||
cat tmp/intermediate.pem >> tmp/expired.pem
|
cat tmp/intermediate.pem >> tmp/expired.pem 2>> "makecerts.log"
|
||||||
|
test_result $?
|
||||||
|
|
||||||
# copy new files
|
# copy new files
|
||||||
if test -s tmp/intermediate.pem -a -s tmp/CACert.pem -a -s tmp/CACertCRL.pem \
|
if test -s tmp/intermediate.pem -a -s tmp/CACert.pem -a -s tmp/CACertCRL.pem \
|
||||||
@ -187,7 +203,6 @@ make_certs() {
|
|||||||
cp tmp/* ./
|
cp tmp/* ./
|
||||||
printf "%s\n" "keys & certificates successfully generated"
|
printf "%s\n" "keys & certificates successfully generated"
|
||||||
printf "%s\n" "makecerts.sh finished"
|
printf "%s\n" "makecerts.sh finished"
|
||||||
rm -f "makecerts.log"
|
|
||||||
else
|
else
|
||||||
printf "%s\n" "makecerts.sh failed"
|
printf "%s\n" "makecerts.sh failed"
|
||||||
printf "%s\n" "error logs ${result_path}/makecerts.log"
|
printf "%s\n" "error logs ${result_path}/makecerts.log"
|
||||||
@ -198,16 +213,13 @@ make_certs() {
|
|||||||
rm -rf "demoCA/"
|
rm -rf "demoCA/"
|
||||||
rm -rf "tmp/"
|
rm -rf "tmp/"
|
||||||
|
|
||||||
# restore settings
|
exit "$result"
|
||||||
LD_LIBRARY_PATH=$TEMP_LD_LIBRARY_PATH
|
|
||||||
|
|
||||||
exit $result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Tests requirement
|
# Tests requirement
|
||||||
if test -n "$(command -v faketime)"
|
if test -n "$(command -v faketime)"
|
||||||
then
|
then
|
||||||
make_certs $1
|
make_certs "$1"
|
||||||
result=$?
|
result=$?
|
||||||
else
|
else
|
||||||
printf "%s\n" "faketime not found in \$PATH"
|
printf "%s\n" "faketime not found in \$PATH"
|
||||||
@ -215,4 +227,4 @@ if test -n "$(command -v faketime)"
|
|||||||
result=1
|
result=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exit $result
|
exit "$result"
|
||||||
|
@ -11,6 +11,7 @@ crl_dir = $dir/demoCA
|
|||||||
new_certs_dir = $dir/demoCA
|
new_certs_dir = $dir/demoCA
|
||||||
database = $dir/demoCA/index.txt
|
database = $dir/demoCA/index.txt
|
||||||
serial = $dir/demoCA/serial
|
serial = $dir/demoCA/serial
|
||||||
|
rand_serial = yes
|
||||||
private_key = $dir/demoCA/intermediate.key
|
private_key = $dir/demoCA/intermediate.key
|
||||||
certificate = $dir/tmp/intermediate.pem
|
certificate = $dir/tmp/intermediate.pem
|
||||||
crl_extensions = crl_ext
|
crl_extensions = crl_ext
|
||||||
@ -20,6 +21,8 @@ policy = policy_loose
|
|||||||
default_startdate = 180101000000Z
|
default_startdate = 180101000000Z
|
||||||
default_enddate = 241231000000Z
|
default_enddate = 241231000000Z
|
||||||
x509_extensions = v3_req
|
x509_extensions = v3_req
|
||||||
|
email_in_dn = yes
|
||||||
|
default_days = 2200
|
||||||
|
|
||||||
[ req ]
|
[ req ]
|
||||||
# Options for the `req` tool
|
# Options for the `req` tool
|
||||||
|
@ -11,6 +11,7 @@ crl_dir = $dir/demoCA
|
|||||||
new_certs_dir = $dir/demoCA
|
new_certs_dir = $dir/demoCA
|
||||||
database = $dir/demoCA/index.txt
|
database = $dir/demoCA/index.txt
|
||||||
serial = $dir/demoCA/serial
|
serial = $dir/demoCA/serial
|
||||||
|
rand_serial = yes
|
||||||
private_key = $dir/demoCA/CA.key
|
private_key = $dir/demoCA/CA.key
|
||||||
certificate = $dir/tmp/CACert.pem
|
certificate = $dir/tmp/CACert.pem
|
||||||
crl_extensions = crl_ext
|
crl_extensions = crl_ext
|
||||||
@ -20,6 +21,9 @@ policy = policy_match
|
|||||||
default_startdate = 180101000000Z
|
default_startdate = 180101000000Z
|
||||||
default_enddate = 260101000000Z
|
default_enddate = 260101000000Z
|
||||||
x509_extensions = v3_intermediate_ca
|
x509_extensions = v3_intermediate_ca
|
||||||
|
email_in_dn = yes
|
||||||
|
default_days = 3000
|
||||||
|
unique_subject = no
|
||||||
|
|
||||||
[ req ]
|
[ req ]
|
||||||
# Options for the `req` tool
|
# Options for the `req` tool
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
# OpenSSL root CA configuration file
|
|
||||||
|
|
||||||
[ ca ]
|
|
||||||
default_ca = CA_default
|
|
||||||
|
|
||||||
[ CA_default ]
|
|
||||||
# Directory and file locations.
|
|
||||||
dir = .
|
|
||||||
certs = $dir/demoCA
|
|
||||||
crl_dir = $dir/demoCA
|
|
||||||
new_certs_dir = $dir/demoCA
|
|
||||||
database = $dir/demoCA/index.txt
|
|
||||||
serial = $dir/demoCA/serial
|
|
||||||
crl_extensions = crl_ext
|
|
||||||
default_md = sha256
|
|
||||||
preserve = no
|
|
||||||
policy = policy_match
|
|
||||||
x509_extensions = usr_cert
|
|
||||||
private_key = $dir/demoCA/CA.key
|
|
||||||
certificate = $dir/tmp/CACert.pem
|
|
||||||
default_startdate = 180101000000Z
|
|
||||||
default_enddate = 210101000000Z
|
|
||||||
|
|
||||||
[ req ]
|
|
||||||
encrypt_key = no
|
|
||||||
default_bits = 2048
|
|
||||||
default_md = sha256
|
|
||||||
string_mask = utf8only
|
|
||||||
x509_extensions = ca_extensions
|
|
||||||
distinguished_name = req_distinguished_name
|
|
||||||
|
|
||||||
[ crl_ext ]
|
|
||||||
authorityKeyIdentifier = keyid:always
|
|
||||||
|
|
||||||
[ usr_cert ]
|
|
||||||
basicConstraints = CA:FALSE
|
|
||||||
subjectKeyIdentifier = hash
|
|
||||||
authorityKeyIdentifier = keyid, issuer
|
|
||||||
extendedKeyUsage = codeSigning
|
|
||||||
|
|
||||||
[ ca_extensions ]
|
|
||||||
basicConstraints = critical, CA:true
|
|
||||||
subjectKeyIdentifier = hash
|
|
||||||
authorityKeyIdentifier = keyid:always,issuer
|
|
||||||
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
|
|
||||||
|
|
||||||
[ policy_match ]
|
|
||||||
countryName = match
|
|
||||||
organizationName = match
|
|
||||||
organizationalUnitName = optional
|
|
||||||
commonName = supplied
|
|
||||||
emailAddress = optional
|
|
||||||
|
|
||||||
[ req_distinguished_name ]
|
|
||||||
countryName = Country Name (2 letter code)
|
|
||||||
stateOrProvinceName = State or Province Name
|
|
||||||
localityName = Locality Name
|
|
||||||
0.organizationName = Organization Name
|
|
||||||
organizationalUnitName = Organizational Unit Name
|
|
||||||
commonName = Common Name
|
|
||||||
emailAddress = Email Address
|
|
@ -38,7 +38,7 @@ modify_blob() {
|
|||||||
sed "s/$initial_blob$zero_blob/$initial_blob$modified_blob/" | \
|
sed "s/$initial_blob$zero_blob/$initial_blob$modified_blob/" | \
|
||||||
xxd -p -r > "changed_$1.$2"
|
xxd -p -r > "changed_$1.$2"
|
||||||
|
|
||||||
../../osslsigncode verify \
|
../../osslsigncode verify -verbose \
|
||||||
-CAfile "${script_path}/../certs/CACert.pem" \
|
-CAfile "${script_path}/../certs/CACert.pem" \
|
||||||
-CRLfile "${script_path}/../certs/CACertCRL.pem" \
|
-CRLfile "${script_path}/../certs/CACertCRL.pem" \
|
||||||
-TSA-CAfile "${script_path}/../certs/ca-bundle.crt" \
|
-TSA-CAfile "${script_path}/../certs/ca-bundle.crt" \
|
||||||
@ -95,7 +95,7 @@ verify_signature() {
|
|||||||
TZ=GMT faketime -f "$5" /bin/bash -c '
|
TZ=GMT faketime -f "$5" /bin/bash -c '
|
||||||
printf "Verify time: " >> "verify.log" && date >> "verify.log" && printf "\n" >> "verify.log"
|
printf "Verify time: " >> "verify.log" && date >> "verify.log" && printf "\n" >> "verify.log"
|
||||||
script_path=$(pwd)
|
script_path=$(pwd)
|
||||||
../../osslsigncode verify \
|
../../osslsigncode verify -verbose \
|
||||||
-CAfile "${script_path}/../certs/CACert.pem" \
|
-CAfile "${script_path}/../certs/CACert.pem" \
|
||||||
-CRLfile "${script_path}/../certs/CACertCRL.pem" \
|
-CRLfile "${script_path}/../certs/CACertCRL.pem" \
|
||||||
-TSA-CAfile "${script_path}/../certs/ca-bundle.crt" \
|
-TSA-CAfile "${script_path}/../certs/ca-bundle.crt" \
|
||||||
@ -153,7 +153,7 @@ verify_leaf_hash() {
|
|||||||
TZ=GMT faketime -f "$4" /bin/bash -c '
|
TZ=GMT faketime -f "$4" /bin/bash -c '
|
||||||
printf "Verify time: " >> "verify.log" && date >> "verify.log" && printf "\n" >> "verify.log"
|
printf "Verify time: " >> "verify.log" && date >> "verify.log" && printf "\n" >> "verify.log"
|
||||||
script_path=$(pwd)
|
script_path=$(pwd)
|
||||||
../../osslsigncode verify \
|
../../osslsigncode verify -verbose \
|
||||||
-CAfile "${script_path}/../certs/CACert.pem" \
|
-CAfile "${script_path}/../certs/CACert.pem" \
|
||||||
-CRLfile "${script_path}/../certs/CACertCRL.pem" \
|
-CRLfile "${script_path}/../certs/CACertCRL.pem" \
|
||||||
-TSA-CAfile "${script_path}/../certs/ca-bundle.crt" \
|
-TSA-CAfile "${script_path}/../certs/ca-bundle.crt" \
|
||||||
|
@ -19,15 +19,11 @@ make_tests() {
|
|||||||
/bin/sh $plik 3>&1 2>> "results.log" 1>&2
|
/bin/sh $plik 3>&1 2>> "results.log" 1>&2
|
||||||
done
|
done
|
||||||
count=$(grep -c "Test succeeded" "results.log")
|
count=$(grep -c "Test succeeded" "results.log")
|
||||||
if test $count -ne 0
|
|
||||||
then
|
|
||||||
skip=$(grep -c "Test skipped" "results.log")
|
skip=$(grep -c "Test skipped" "results.log")
|
||||||
fail=$(grep -c "Test failed" "results.log")
|
fail=$(grep -c "Test failed" "results.log")
|
||||||
printf "%s\n" "testall.sh finished"
|
printf "%s\n" "testall.sh finished"
|
||||||
printf "%s\n" "summary: success $count, skip $skip, fail $fail"
|
printf "%s\n" "summary: success $count, skip $skip, fail $fail"
|
||||||
else # no test was done
|
return $fail
|
||||||
result=1
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rm -rf "${result_path}"
|
rm -rf "${result_path}"
|
||||||
|
Reference in New Issue
Block a user