Skip to content

Allow accessing raw created/modified FILETIME - #82

Open
roblabla wants to merge 1 commit into
mdsteele:masterfrom
roblabla:raw-created-modified
Open

Allow accessing raw created/modified FILETIME#82
roblabla wants to merge 1 commit into
mdsteele:masterfrom
roblabla:raw-created-modified

Conversation

@roblabla

@roblabla roblabla commented Sep 5, 2026

Copy link
Copy Markdown

I'm currently working on a crate verifying authenticode signatures for MSI, and using the CFB crate to parse the MSI files to achieve this.

To verify an MSI signature, it is necessary to access the raw created/modified values, as they are part of the authenticode hash1. While it's technically possible to get the FILETIME back from the SystemTime, it's a lossy operation (a FILETIME that doesn't fit in a SystemTime converts it to SystemTime::UNIX_TIME). It'd be nicer to just have access to the raw value so we can guarantee we're hashing the correct value.

This MR adds two new methods to Entry to access the raw FILETIME values.

Footnotes

  1. http://github.com/ralphje/signify/blob/master/signify/authenticode/signed_file/msi.py#L193-L194

This is necessary to correctly compute the authenticode hash of an MSI
file[0]. While it's technically possible to get the FILETIME back from
the SystemTime, it's a lossy operation (a FILETIME that doesn't fit in
a SystemTime returns UNIX_TIME). It'd be nicer to just have access to
the raw value so we can guarantee we're hashing the correct value.

[0]: http://github.com/ralphje/signify/blob/master/signify/authenticode/signed_file/msi.py
@francisdb

Copy link
Copy Markdown
Contributor

@mdsteele mind approving CI run?

@francisdb francisdb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, the accessors are a sensible addition. One thing to check before merging, because I think it affects your use case:

Stream timestamps are zeroed by the permissive parser. DirEntry::read_from replaces a non-zero creation/modification time on a stream entry with zero under permissive validation (the default for open), and strict mode rejects such a file (direntry.rs, the two Timestamp::zero() assignments near lines 229 and 239). signify's MSI authenticode hash covers the timestamps of every non-root entry, streams included. So for an MSI whose streams carry timestamps, created_raw()/modified_raw() return 0 rather than the stored value, and the doc comment ("as it is stored in the file") does not hold.

I checked with a file where a storage and a stream both have their FILETIMEs patched to non-zero, opened with CompoundFile::open:

storage: created_raw=0x1d0123456789abc modified_raw=0x1d0fedcba987654
stream:  created_raw=0x0                modified_raw=0x0

Suggestion: keep the values as read for streams in permissive mode (or keep raw copies alongside the normalized ones), and add a test along those lines so the raw accessors are covered.

Comment thread src/internal/entry.rs
self.creation_time.to_system_time()
}

/// Returns the raw FILETIME value of [`created`], as it is stored in the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unresolved intra-doc link (rustdoc warns no item named \created` in scope); [Entry::created]` resolves.

Comment thread src/internal/entry.rs
self.modified_time.to_system_time()
}

/// Returns the raw FILETIME value of [`modified`], as it is stored in the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here: [Entry::modified].

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants