• Making a self-signed SSL certificate (and trusting it) in PowerShell

    I recently came across a new PowerShell cmdlet for creating self signed certificates in PowerShell:

    $cert = New-SelfSignedCertificate -DnsName localhost, $env:COMPUTERNAME
            -CertStoreLocation Cert:\LocalMachine\My
    

    This cmdlet is actually really helpful since it lets you specify subject alternative names in the certificate as well. The DnsName parameter uses the first value for the Common Name, and all of them for SANs. Since the cmdlet returns an X509Certificate2 object, it’s easy enough to use in other .NET API’s as well, such as adding it to the Trusted Root Authority:

    $rootStore = New-Object System.Security.Cryptography.X509Certificates.X509Store -ArgumentList Root, LocalMachine
    $rootStore.Open("MaxAllowed")
    $rootStore.Add($cert)
    $rootStore.Close()
    

    And even creating an SSL binding to an IIS Web Site:

    New-WebBinding -Name "Default Web Site" -IPAddress "*" -Port 443 -Protocol https
    pushd IIS:\SslBindings
    $cert | New-Item 0.0.0.0!443
    popd
    

    This is a handy little Cmdlet, though it lacks some flexibility, such as specifying the validity period and RSA key size (though the default 2048 is just fine).

  • Compiler warnings are your friend

    I’m a big fan of tooling to speed of development. I’m also an advocate of ensuring that your tools aren’t a crutch – more of a performance enhancer. Generally, tools such as IDEs, compilers, and code generation, are there to save time and effort – as long as you understand what they are doing for you.

    That’s why I’m always surprised when people ignore the help their tool is trying to give them. A particular one for me is compiler warnings, and people or teams having hundreds or thousands of compiler warnings.

    General responses I get when asked about it are, “Oh, that’s just the compiler complaining, it’s safe to ignore them.” Problem with that though, is it makes it impossible to find genuinely helpful compiler warnings in the sea.

    C# Warnings

    There are lots of ways to solve the problem with compiler warnings.

    One option is to just fix the issue the compiler is warning about. The compiler warning is making a suggestion, and sometimes (or most of the time) it’s right – so fix the problem. If the compiler tells you a region of code is unused, then you can remove it safely. These are always the most helpful warnings and why you want a pristine warning list. Often enough, the compiler will catch something that’s easy to gloss over, such as a double free, precision loss when casting numeric types, and the like.

    Warnings can be ignored, too. Some warnings, you or your team might just not find helpful, or produce more noise than help. Any good compiler comes with a way to disable warnings, either with a code pragma for certain regions of code, or a compiler flag to completely disable the warning. One that comes up for me often enough is in some places compiler directives are used for DEBUG builds, which can confuse Visual Studio about code that will never run.

    #pragma warning disable 0162
    #if DEBUG
            return TimeSpan.MaxValue;
    #endif
            return new TimeSpan(0,5,0);
    #pragma warning restore 0162
    

    Normally, Visual Studio would give a compiler warning that the second return value is unreachable while in debug configuration.

    I try to avoid this kind of code in the first place – but sometimes it cannot be helped. Various other compilers support a similar notion, for example Clang:

    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wunused-variable"
    
    //Region
    
    #pragma clang diagnostic pop
    

    Sometimes compiler warnings are introduced with no clear plan on how to clean the up, and they’ll sit there for ages. A good example might be obsoleting a method or function that is called in hundreds of places.

    [Obsolete("This is obsolete and should not be used.")]
    public void ObsoleteMethod()
    {
            //...
    }
    

    I’m generally not a fan of obsoleting methods, except in the rare case that you’re an API or SDK provider and you need to inform consumers of your library. Otherwise, favoring refactoring and completely removing the method is a better option.

    In some circumstances some warnings might be useful as actual errors, too. Security warnings are generally some that I’ve taken to escalating to a full error, such as using strcpy or Objective-C’s violation of self = [super init] rule.

    In all, I see compiler warnings often ignored when they provide tremendous value to you or a team. It can be a bit tedious to keep compiler warnings “clean”, but it’s well worth the effort.

  • Using ECC for an SSL Certificate

    Recently I’ve been toying with the idea of using ECCDSA instead of RSA for SSL certificates. Using an ECC key of 256 is approximately as strong as a 3072-bit RSA key, which is what drew me towards them. However I found it a little difficult to get the Certificate Authority to issue the right kind of certificate. Eventually I got it working using CertReq.exe, here is the INF I used to generate the certificate.

    [Version]
    Signature="$Windows NT$"
    
    [NewRequest]
    Subject = "CN=yourcommonname"
    Exportable = FALSE
    KeyLength = 256
    KeyUsage = 0xA0
    MachineKeySet = TRUE
    KeySpec = 0
    ProviderName = "Microsoft Software Key Storage Provider"
    ProviderType=12
    KeyAlgorithm = "ECDSA_P256"
    HashAlgorithm = "SHA256"
    
    [Strings]
    szOID_SUBJECT_ALT_NAME2 = "2.5.29.17"
    szOID_ENHANCED_KEY_USAGE = "2.5.29.37"
    szOID_PKI_KP_SERVER_AUTH = "1.3.6.1.5.5.7.3.1"
    
    [Extensions]
    %szOID_SUBJECT_ALT_NAME2% = "{text}dns=domain1&dns=domain2"
    %szOID_ENHANCED_KEY_USAGE% = "{text}%szOID_PKI_KP_SERVER_AUTH%"
    
    [RequestAttributes]
    CertificateTemplate= WebServer
    

    With this template I was issued a ECDSA_P256 certificate, which is exactly what I wanted. The usage of a SAN is optional, however it I needed to specify it as well, so I left it here.

  • Passing Public Keys Between Objective-C OpenSSL and .NET

    I had a bit of a fun time working on a simple key exchange mechanism between C# and Objective-C using OpenSSL. My goal was on the Objective-C side to generate a public/private key pair, and pass the public key to C# in a way that I could use it to encrypt small amounts of data (like a symmetric key).

    This proved to be a little challenging to me, as I didn’t want to resort to using a 3rd party solution in .NET like BouncyCastle or a managed OpenSSL wrapper. Turns out, it’s not that hard, if just a little under-documented. Starting with Objective-C, here’s how I am generating an RSA key pair.

    Assuming you have an RSA* object from OpenSSL, you can export the public key like so:

    -(NSData*)publicKey {
        int size = i2d_RSAPublicKey(_rsa, NULL);
        unsigned char* temp = OPENSSL_malloc(size);
        //the use of a temporary variable is mandatory!
        unsigned char* copy = temp;
        int keySize = i2d_RSAPublicKey(_rsa, &copy);
        NSData* data = nil;
        if (keySize > 0) {
            data = [[NSData alloc] initWithBytes:temp length:keySize];
        }
        OPENSSL_free(temp);
        return data;
    }
    

    For illustrative purposes: Don’t forget to do error checking!

    So now we have an NSData, but how is this public key actually stored? How can I use this in .NET?

    The first thing to understand is the format by what format i2d_RSAPublicKey exports data. This exports the data in ASN.1 DER format, and getting that into an RSACryptoServiceProvider is possible with no 3rd party support.

    private static readonly byte[] _nullAsnBytes = new byte[] {0, 5};
    
    public RSACryptoServiceProvider GetCryptoServiceProvider(byte[] asnDerPublicKey)
    {
        const string RSA_OID = "1.2.840.113549.1.1.1";
        var oid = new Oid(RSA_OID);
        var asnPublicKey = new AsnEncodedData(oid, asnDerPublicKey);
        var nullAsnValue = new AsnEncodedData(_nullAsnBytes);
        var publicKey = new PublicKey(oid, nullAsnValue, asnPublicKey);
        return publicKey.Key as RSACryptoServiceProvider;
    }
    

    The 1.2.840.113549.1.1.1 value is the OID for RSA, or the actual header name szOID_RSA_RSA. We use a ASN.1 value of null ({0, 5}) for the parameters, and hen we pass the AsnEncodedData to the PublicKey class, from which we can obtain an RSACryptoServiceProvider from the public key.

    Together, these two code snippets allow working with RSA public keys in Objective-C (iOS or Mac) and in .NET.

  • Unzipping Files with Powershell in Server Core – The New Way

    I know this topic has been blogged to death, but every solution I’ve found that does this uses the Windows Shell, something along these lines:

    $shellApplication = new-object -com shell.application
    $zipPackage = $shellApplication.NameSpace($zipfilename)
    $destinationFolder = $shellApplication.NameSpace($destination)
    $destinationFolder.CopyHere($zipPackage.Items())
    

    That’s all fine and well, but in Server Core, this isn’t going to work.

    What the script is doing is trying to automate the Windows Shell, which is exactly what Server Core doesn’t have. This will fail with HRESULT E_FAIL. So what do do?

    I got a bit frustrated by this – how could a scripting language that is suppose to be powerful and flexible, not be able to unzip a zip file? Unix has had this for ages with unzip.

    It turns out that in .NET Framework 4.5, there is a ZipFile class that is simple enough to use.

    Knowing this, the work was trivial.

    #Load the assembly
    [System.Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") | Out-Null
    #Unzip the file
    [System.IO.Compression.ZipFile]::ExtractToDirectory($pathToZip, $targetDir)
    

    You’ll need the .NET Framework 4.5 installed for this to work, which can be installed easily enough on Server 2012 Core like so:

    Install-WindowsFeature Net-Framework-45-Core
    

    This will of course also work even if you aren’t using Server Core, and are using the full installation of Windows Server.

    Big thanks to Peter Hahndorf for putting me in the right direction.