Proposed Workaround for C++/CLI Assembly Signing Issue with VS2010 SP1

Proposed Workaround for C++/CLI Assembly Signing Issue with VS2010 SP1

  • Comments 14

Hi, my name is Amit Mohindra and I’m Program Manager with the MS Visual C++ team.

Recently we were made aware of a change in SP1 which affected the signing process for assemblies (C++/CLI assemblies) as part of the following forum post:

http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/4b8f353d-8153-45d6-b286-10403cdf159a?prof=required

The issue in SP1 would affect folks who are using switches on the linker to sign the assemblies as part of their build. To sign assemblies you have to explicitly set the this property by right clicking on the project to bring up the properties dialog and then under Configuration Properties->Linker->Advanced set the "Key File" property to use a signing key. By default this property is empty so if you haven't explicitly set it you should be unaffected.

In case you are using the linker switches in your CLI projects to sign the final assembly then please follow the contents of this blog to unblock yourself.

We are very sorry for the inconvenience caused by this assembly signing issue. We recognize that this change in SP1 has introduced an unintentional breaking change. This is indeed a bug in VS2010 SP1.

I will start by giving you a little bit of background into what the issue was in VS2010 RTM, how our change in SP1 broke your projects and then finally the workaround you could apply to unblock yourselves.

 

Background

  1. VS2010 RTM
    1. Assemblies built using C++ projects were not getting signed at all.
      1. This was happening since mt.exe would invalidate the signature performed by the preceding Link step (which signs the binary). This is expected behavior.
      2. To counter the invalidation the build process runs and additional “LinkEmbedManifest” step to re-sign the assembly after mt.exe is done embedding the manifest.
      3. However, in VS2010 RTM step 1.a.B was being skipped. Thus, the assemblies were not getting signed.
    2. So we recommended a workaround to run “sn.exe –R <assembly> <KeyFile>” (e.g. sn -R debug\CLRConsole.exe C:\mykey.snk)  as part of the custom build step and to sign the assembly.
  2. VS2010 SP1 (fix that broke you)
    1. The main reason why “LinkEmbedManifest” step was getting skipped in VS2010 RTM was that during the build process our decision logic to trigger this step did not have enough information. The decision logic required evaluated values for “Key File” and “Delay Sign” (properties on the Linker). These values were stored as “Item Definition Group”  (IDG) in the project file and IDG’s are evaluated at a later stage than the decision point and thus were unavailable.
    2. To fix the issue we made “Key File” and “Delay Sign” MSBuild properties (<PropertyGroups>) instead and since MSBuild properties are evaluated early on we would now be able to decide whether to run “LinkEmbedManifest” step or not. With this change we would have eliminated the need of a custom build step (as suggested in above in 1.a.B)
    3. As part of the SP1 readme (http://go.microsoft.com/fwlink/?LinkId=210711 – section 2.4.1.2) we suggested refactoring of the project to make signing work. The suggestion was to redefine the “Key File” and “Delay Sign” property for the project using the IDE.
    4. However there were two issues with this solution:
      1. First, a typo in one our build files makes the above suggestion not work when you are targeting the Win32 configurations to build your projects.
      2. Second, we did not recognize that people using the old method and the VS2010 RTM workaround (mentioned above in 1.a.B) would be broken.

 

Workaround

The following workaround enables you to fix the two issues described above in 2.d.A and 2.d.B. You can work around this issue in two ways.

1. Change each project in your solution and redefine the “Key File” and “Delay Sign” properties on the linker. To do that follow these steps:

· Fix the typo in the build process (2.d.A):

  1. Open cmd prompt as administrator
  2. Go to %ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32
  3. Run “notepad Microsoft.Cpp.Win32.targets” (x64 targets are fine)
  4. Find the “LinkEmbedManifest” target (search for <Target Name="LinkEmbedManifest")
  5. Under the above target and in the task “<Link” perform the following steps.
  6. Change property  DelaySign
    1. From :       DelaySign  ="%(Link.DelaySign)"
    2. To :         DelaySign  ="$(LinkDelaySign)"
  7. Change property  KeyFile
    1. From :       KeyFile    ="%(Link.KeyFile)"
    2. To:         KeyFile    ="$(LinkKeyFile)"

· Redefine the “Key File” and “Delay Sign” properties used for signing your project (2.d.B):

  1. Right click on your project to bring up the properties page.
  2. Go to Configuration Properties->Linker->Advanced
  3. Overwrite the property “Key File” with your original key file. (for e.g. myfile.snk)
  4. This workaround eliminates the need of a custom build step (as described in background section VS2010RTM-1.2)
  5. If you want to use the same project in VS2010 RTM and VS2010 SP1 make sure that when you redefine these properties they match their original value as set in VS2010 RTM.

2. Or, If you have a lot of projects and don’t want do step 1 (above) , alternatively you could make the following changes to resurrect your VS2010 RTM behavior:

  1. Open cmd prompt as administrator
  2. Go to “%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32
  3. Run “notepad Microsoft.Cpp.Win32.targets
  4. Move to “Link” target (search for <Target Name="Link")
  5. Add the following lines right after the first  “<PropertyGroup>” definition  and before the “<Link” task
    <PropertyGroup>
        <LinkDelaySign Condition="'$(LinkDelaySign)' == ''">%(Link.DelaySign)</LinkDelaySign>
        <LinkKeyFile Condition="'$(LinkKeyFile)' == ''">%(Link.KeyFile)</LinkKeyFile>
    </PropertyGroup>
  6. Find the “LinkEmbedManifest” target (search for <Target Name="LinkEmbedManifest")
  7. Under the above target and in the task “<Link” perform the following steps.
  8. Change property  DelaySign
    1. From :       DelaySign   ="%(Link.DelaySign)"
    2. To :         DelaySign   ="$(LinkDelaySign)"
  9. Change property  KeyFile
    1. From :       KeyFile     ="%(Link.KeyFile)"
    2. To:         KeyFile     ="$(LinkKeyFile)"
  10. Repeat the steps 1 to 5 for “%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\Platforms\x64
  11. Note that this solution will move you back to the VS2010 RTM behavior and you would still need to use the original workaround to sign your assemblies using sn.exe in the custom build step.

Thank you for helping us improve quality of the product. We understand that this change has caused much pain to you and for which we are sorry. Meanwhile we are also looking at other avenues to provide you with this fix.

 

Thanks,
Amit

  • This is all very confusing to me. What is signing and why do we need it? I have not installed SP1, does that mean I still have a problem that I have to manually fix? Can't I just wait for SP1.1?

  • By the way my product is 100% C++ (no CLI or .Net).

  • Hi,

    Recently we were made aware of a change in Sp1 which affected the signing process for assmeblies (C++/CLI assemblies) as part of the following forum post:

    social.msdn.microsoft.com/.../4b8f353d-8153-45d6-b286-10403cdf159a

    The issue in Sp1 would affect folks who are using switches on the linker to sign the assemblies as part of their build. To sign assemblies you have to explicitly set the this property by right clicking on the project to bring up the properties dialog and then under Configuration Properties->Linker->Advanced set the "Key File" property to use a signing key. By default this property is empty so if you haven't explicitly set it you should be unaffected.

    More details on the C++ signing process are here: msdn.microsoft.com/.../ms235305.aspx

    @confucius If your product is 100% native (no CLI) then this issue should not affect you.

  • it would be nice if you could edit your post to clearly say C++/CLI instead of C++, then.

    It's rather confusing when a blog post talking about C++/CLI just says "C++". They're different languages, remember - and I seem to recall that Microsoft was very confident during the standardization of it, that there was *NO* chance anyone would ever get them mixed up due to the similar names. So please, at least use the right name when you're trying to convey information to us.

  • Hey,

    Feedback recieved. We are already working on editing the post.

    Thanks,

    Amit

  • I am getting the below error

    error MSB4096: The item "Debug\\XXX.dll.embed.manifest.res" in item list "Link" does not define a value for metadata "LinkDelaySign".  In order to use this metadata, either qualify it by specifying %(Link.LinkDelaySign), or ensure that all items in this list define a value for this metadata. C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\Microsoft.Cpp.Win32.Targets 399

    What have i done wrong?

  • What if you use a key container instead of a key file? Do the same steps apply?

  • So workaround 1 just fixes the error message, but I still need to sign the assembly in the post-build-step using sn?

    At least thats how it looks on my comp. Without the post-build-step the assembly will not be signed.

  • I dug a little deeper and tested some more: it seems all I really need to do is to set delaysign to true, since this setting is not automatically migrated from RTM to SP1?

  • @Sam- with workaround #1 you shouldnt need the post-build step to sign the binary. Does it not work if you set delaysign to false? If delay sign is set to false then the binary should be signed.

    @Dan - note that you need to replace the Delay sign property as DelaySign  ="$(LinkDelaySign)". Note that there are no "." in the name. Please double check the changes you made.

  • I had to use Sam Jost's suggestion and use delaysign in addition to keeping the custom build event. If I just used the KeyFile and DelaySign:NO then the assembly was not properly signed.

  • @Dan

    I also got this message.

    It truns out that I hadn't read carefully enough.

    It isn't sufficient to delete '.'. You must also change '%' to '$' in the same line.

  • If you use the c++/CLI in a C# Projekt wich should be registerd as COM Interop DELAYSIGN must be NO,

    otherwise you get

    Cannot register assembly "...".

    Could not load file or assembly '...' or

    one of its dependencies. Strong name validation failed. (Exception from HRESULT: 0x8013141A)

  • In addition to the steps set out in (1) I needed to make two additional changes to get my project compiling:

    (i) I reset Configuration Properties->Manifest Tool->Input and Output->Output Manifest File from being empty to inheriting from parent/project defaults to remove the error:

     error MSB4044: The "WriteLinesToFile" task was not given a value for the required parameter "File".

    I'm not sure why the Ouput Manifest File needs to be specified and written to even when "Embed Manifest=true": It would be nice to have some reassurance that the Embed Manifest option wasn’t just being completely ignored;

    (ii) Reading

      connect.microsoft.com/.../c-cli-project-fails-to-build-if-using-delay-sign-when-manifest-generation-is-not-used

    there is a suggested modification to

     %Programfiles%\msbuild\microsoft.cpp\v4.0\Microsoft.cppcommon.targets

    which when applied removes the error:

      "mt.exe : general warning 810100b3: XXX is a strong-name signed assembly and embedding a manifest invalidates the signature. You will need to re-sign this file to make it a valid assembly."

Page 1 of 1 (14 items)