Understanding code signing



  • I understand signing is a good thing... I was looking at how the end user sees things and was a bit surprised...

    I run my signed exe, it runs.
    I edit the binary (open in VS, modify versioninfo in resource editor, save)
    I run the modified exe, it runs, no warnings. (Turns out the signing is stripped in the previous save)

    To the end user, there is no change. Ignoring wrong side of watertight door and all, would the code itself have to check "am I signed" at run time? Or is signing really only good for the install process and auditing of binaries (yeah, it's signed - good)?

    Another check - I used a hex editor and changed the manifest - the signing remained. And the exe started with no issue. Ok, THAT was unexpected... This only way to know it's compromised is to look at the properties of the exe, and then drill down into the details of the cert.

    Am I confused in thinking Windows shouldn't let an exe with an invalid cert run? Or is that just because this is a dev system (VS2010,2015,2017) so things are a little more ... um ... lenient.

    edit: If it matters, I should mention, I'm looking at win32 EXEs (from c++ source).



  • It depends on system configuration. By default Windows will let you run anything, but UAC prompts might be different if the certificate has been tampered with or is completely absent. In an enterprise environment you're more likely to find software restriction policies in place which block execution of unsigned assemblies (e.g. through AppLocker).



  • @alexmedia So in other words, a typical home user would have no idea the binary they're running has been tampered with... Eek! It seems to me that the system should scream bloody murder if I'm trying to run something that has been tampered with!



  • Code Signing [*.snk] does not have any relationship to tampering. [many think it does, but it does not].



  • @thecpuwizard Then what is code signing for? Ensuring the signature itself is valid and nothing else?



  • @lb_ said in Understanding code signing:

    @thecpuwizard Then what is code signing for? Ensuring the signature itself is valid and nothing else?

    Used alone, it is really about versioning and tracking a source that was involved at some point. When added to Authenticode (or similar) and other techniques, it is a cross check.



  • From the MSDN documentation:

    Why strong-name your assemblies?
    When you reference a strong-named assembly, you can expect certain benefits, such as versioning and naming protection. Strong-named assemblies can be installed in the Global Assembly Cache, which is required to enable some scenarios.

    Strong-named assemblies are useful in the following scenarios:

    • You want to enable your assemblies to be referenced by strong-named assemblies, or you want to give friend access to your assemblies from other strong-named assemblies.

    • An app needs access to different versions of the same assembly. This means you need different versions of an assembly to load side by side in the same app domain without conflict. For example, if different extensions of an API exist in assemblies that have the same simple name, strong-naming provides a unique identity for each version of the assembly.

    • You do not want to negatively affect performance of apps using your assembly, so you want the assembly to be domain neutral. This requires strong-naming because a domain-neutral assembly must be installed in the global assembly cache.

    • When you want to centralize servicing for your app by applying publisher policy, which means the assembly must be installed in the global assembly cache.


  • :belt_onion:

    @thecpuwizard said in Understanding code signing:

    From the MSDN documentation:

    Why strong-name your assemblies?
    When you reference a strong-named assembly, you can expect certain benefits, such as versioning and naming protection. Strong-named assemblies can be installed in the Global Assembly Cache, which is required to enable some scenarios.

    Strong-named assemblies are useful in the following scenarios:

    • You want to enable your assemblies to be referenced by strong-named assemblies, or you want to give friend access to your assemblies from other strong-named assemblies.

    • An app needs access to different versions of the same assembly. This means you need different versions of an assembly to load side by side in the same app domain without conflict. For example, if different extensions of an API exist in assemblies that have the same simple name, strong-naming provides a unique identity for each version of the assembly.

    • You do not want to negatively affect performance of apps using your assembly, so you want the assembly to be domain neutral. This requires strong-naming because a domain-neutral assembly must be installed in the global assembly cache.

    • When you want to centralize servicing for your app by applying publisher policy, which means the assembly must be installed in the global assembly cache.

    Which is talking about the .net version of "strong naming", not the colquial version of "executable associated with a certificate"

    [insert blakeyrant about things not meaning what they sound like and this is why our lives are shitty]



  • @sloosecannon said in Understanding code signing:

    Which is talking about the .net version of "strong naming", not the colquial version of "executable associated with a certificate"

    And which is also consistent with the information in the original post, hence there being a reasonable probability that this is what the OP was referring to.... :)

    [ps: My life is fantastic - but I get the point regarding unclear meanings; about 75% of my presentations start with a "for the purposes of this discussion, these words mean these things...".]


  • Discourse touched me in a no-no place

    @dcon said in Understanding code signing:

    So in other words, a typical home user would have no idea the binary they're running has been tampered with... Eek! It seems to me that the system should scream bloody murder if I'm trying to run something that has been tampered with!

    There's a long history of unsigned-but-actually-valid code being deployed in the wild on Windows. We're stuck with it. More locked down ecosystems like iOS and Android (and maybe the parts of Windows that support their phone and tablet versions) have much more code signing involved; I believe that it's mostly checked during installation for performance reasons.


  • :belt_onion:

    @dkf said in Understanding code signing:

    @dcon said in Understanding code signing:

    So in other words, a typical home user would have no idea the binary they're running has been tampered with... Eek! It seems to me that the system should scream bloody murder if I'm trying to run something that has been tampered with!

    There's a long history of unsigned-but-actually-valid code being deployed in the wild on Windows. We're stuck with it. More locked down ecosystems like iOS and Android (and maybe the parts of Windows that support their phone and tablet versions) have much more code signing involved; I believe that it's mostly checked during installation for performance reasons.

    He's saying Windows should complain if there's a signature, but it's invalid. I'd tend to agree - that is the same approach we take to http vs https, after all. If they make no attempt to prove identity, that's all well and good, but if it's signed but invalid, it should scream bloody murder



  • I have another signing / cert management question...

    When I originally bought my cert, that process auto-installed it into the machine. I can then signtool sign /n "My Name" .... Interestingly, searching for "My Name" in certmgr fails.

    Time passes. I spin up a new VM with a different compiler and install the cert (by dbl-clicking the pfx file and running thru the import process - I put it into Local Machine, not Current User if that matters). Searching for "My Name" in certmgr succeeds. But running signtool as before fails. I'm forced to use the pfx file to sign. Is there some trick to importing the pfx such that the /n option works?

    Edit: never mind... Enhancing my google-foo said that when imported into LM, I need to include the /sm option. Food. I need food.


Log in to reply