Renewing Self-Signed “Temporary” Certificates

If you’re like me—writing internal apps for a small company—you create your own self-signed certificates when publishing a ClickOnce application. Visual Studio will create these certificates for you automatically on the first publish, but they’ll only be good for a couple of years. That’s when you find yourself under pressure, updating a malfunctioning application, and suddenly you’re getting an error when trying to push out your fixes.

A great tool to renew your certificates is RenewCert, written by Cliff Stanford. Using this tool, you can quickly extend the expiration date of your signing certificate to 5 years from the current date. Much thanks are due to Cliff for figuring this all out! This stuff isn’t really documented anywhere.

But I found a few limitations:

  1. I couldn’t run it in a setting without VC++ installed. The author acknowledges this issue, but with walking the dependencies I couldn’t manage to find them all. I had to run this on a remote computer so it was a deal-breaker.
  2. I couldn’t get the thing to compile on my system. I’ve rooted around C++ apps before and I could probably figure it out, but I just didn’t want to.
  3. Because I couldn’t compile I couldn’t extend the expiration date beyond 5 years, like 25 years for example.
  4. I wanted to use it as part of a tool to move a ClickOnce app from one location to another. I needed a way to determine if a certificate was out of date by running a command line tool and checking the [generic]errorlevel[/generic] output.

So I set about rewriting the app in C#. The hardest part was tracking down all the P/Invoke declarations. The [generic]CertCreateSelfSignCertificate[/generic] API was particularly finicky. The rewrite works the same way as the original with a hard-coded year, but you can always hard-code your own or add support for an additional argument.

New features include:

  • If you don’t supply a CN, it will look up the original and use it rather than a placeholder.
  • You can use a “/e” argument to see if the given certificate has expired.
  • All cleanups are wrapped in a [csharp]try..finally[/csharp] so you’re less likely to destabilize the system (which I did a couple of times and had to restart).

Here’s a complete example:

[shell linenumbers=”false”]
set certFile=C:\My Project\MyCert.pfx
renewcert “%certFile%” /e
if %errorlevel% equ 0 echo Certificate is not expired. & goto SkipCertRenew
echo Certificate is out of date and must be renewed!
renewcert “%certFile%” “%certFile%”
if %errorlevel% neq 0 echo Error %errorlevel% renewing certificate.
:SkipCertRenew
pause
[/shell]

Like the original author, I got it working and stopped, so it’s not the prettiest thing in the world—mea culpa. But this should be easier to extend to suit your needs.

Download: RenewCert.zip (for VS 2010)

6 thoughts on “Renewing Self-Signed “Temporary” Certificates

  1. Thank for this it has got me out of trouble a couple of times, when Microsoft took project deployment out of VS I thought the replacement ClickOnce was a great idea and it revolutionised the way I gave updates to my clients until applications were more than a year old

  2. Well, I tried this by compiling (also in debug) in VS 2015 and on Windows 7 machine and it threw AccessViolation exception always at the CertNameToStr call (line 261 in main). I guess I’ll just

  3. I gave it a try in VS2017 on Win10 64bit and also got an AccessViolation at the CertNameToStr call. Looks like a bug but the code is certainly “finickity” !

  4. The fix is to change the signature of CertNameToStr in Crypt.cs from

    [DllImport(“crypt32.dll”, CharSet = CharSet.Auto)]
    public static extern int CertNameToStr(X509Encoding dwCertEncodingType, ref CRYPT_DATA_BLOB pName, CertNameType dwStrType, ref string psz, int csz);

    to

    [DllImport("crypt32.dll", CharSet = CharSet.Auto)]
    public static extern int CertNameToStr(X509Encoding dwCertEncodingType, ref CRYPT_DATA_BLOB pName, CertNameType dwStrType, string psz, int csz);

    then just change the method call line in Program.cs from

    if ((d = Crypt.CertNameToStr(Crypt.X509Encoding.ASN_Encodings, ref certNameBlob, Crypt.CertNameType.CERT_X500_NAME_STR, ref buffer, 1024 * sizeof(char))) != 0)

    To

    if ((d = Crypt.CertNameToStr(Crypt.X509Encoding.ASN_Encodings, ref certNameBlob, Crypt.CertNameType.CERT_X500_NAME_STR, buffer, 1024 * sizeof(char))) != 0)

    ie the output buffer string is passed by value not reference.

    After that it worked fine for me.

  5. Hi all,

    The tool is still working, however, it converts a test certificate from SHA256 to SHA1. And SmartScreen now has some serious trust issues with my certificate.

    Does anyone know if the tool can be changed to create the certificate as SHA256?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.