Create valid self-signed certificates using OpenSSL


I was debugging a WebSocket connection failing with error net::ERR_INSECURE_RESPONSE, in Chrome, when I learnt that the self-signed certificate I was using was missing subject alternative names. This post brings together information I found in several different places, to create valid self-signed server certificates, using OpenSSL, that work with internet browsers such as Chrome.

valid-certificate-iis.png

To create a certificate with subject alternative names

openssl req -x509 -newkey rsa:4096 -nodes -subj '/CN=localhost' -keyout key.pem -out cert.pem -days 365 -config openssl.cnf -extensions req_ext

Additional distinguished name properties may be specified by changing the subj option

-subj "/C=US/ST=private/L=province/O=city/CN=hostname.example.com"

A minimalist openssl.cnf file that contains req_ext extension section with subjectAltName

[ req ]
distinguished_name = req_distinguished_name
req_extensions     = req_ext
[ req_distinguished_name ]
[ req_ext ]
subjectAltName = @alt_names
[alt_names]
DNS.1   = localhost
DNS.2   = example.com

Print certificate to view subject alternative names and thumbprint/fingerprint

openssl x509 -noout -text -fingerprint -in cert.pem

Create pfx from private key and certificate in pem format

openssl pkcs12 -inkey key.pem -in cert.pem -export -out key.pfx

Create crt file from certificate in pem format

openssl x509 -outform der -in cert.pem -out cert.crt

Add private key to the appropriate key store and reconfigure server application.

Add certificate file to trusted root authorities key store. Restart the browser. It should be happy with the certificate provided by the server.

On Windows, PowerShell’s New-SelfSignedCertificate command can also be used to automate self-signed certificate creation and installation.

Advertisements

Export private key in pfx or p12 file to pem format


The following openssl command can be used to export private key in a pfx or p12 file to pem

openssl pkcs12 -nodes -in file.pfx -out key.pem -nocerts

If you need the public key for the private key in key.pem

openssl rsa -in key.pem -out key.pub -pubout

If you need information on the public key (modulus, exponent…)

openssl rsa -in key.pem -pubout -text

OR

openssl rsa -pubin -in key.pub -text

If you need to create pfx from private key and certificate in pem format

openssl pkcs12 -inkey key.pem -in cert.pem -export -out file.pfx

Self-signed code signing certificates


Some setup and application executables need to be signed so that they are not flagged as a security risk by security software on Windows. Especially those that have virus-like behavior such as embedded executable resources that are extracted, and executed.

The following steps were performed on Windows, from the Developer Command Prompt installed by Visual Studio.

To generate self-signed certificate for code signing, run

makecert.exe -n CN=Test.org(Test) -r -h 0 -eku "1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.10.3.13" -e 12/31/2017 -pe -sv Test.pvk Test.cer

Here’s a brief overview of the command line
-n subject name
-r create self-signed certificate
-h max height of tree below this cert
-eku comma separated enhanced key usage ids
-e expiration date
-pe private key is exportable
-sv private key file name

You may specify a password or leave it empty.

To convert self-signed certificate to PFX format for usage with SignTool, run

Pvk2Pfx -pvk Test.pvk -spc Test.cer -pfx Test.pfx

To use SignTool to sign an executable, run

SignTool sign /fd SHA256 /a /f Test.pfx filepath.exe

Install certificate (Test.cer) to local machine before running executable.Screen Shot 2017-02-23 at 09.17.03.png

Signing a Wix Toolset setup bundle

You cannot just sign the setup bundle executable and get it to work, because the embedded executable (engine.exe) remains unsigned and will be flagged as a security risk. Use the following steps to prepare setup bundle for installation without being flagged as a security risk.

First, detach the engine from setup as follows

insignia -ib setup.exe -o engine.exe

Sign engine.exe with your certificate using SignTool

SignTool sign /fd SHA256 /a /f Test.pfx engine.exe

Re-attach the signed engine.exe to the bundle

insignia -ab engine.exe setup.exe -o setup.exe

Sign setup.exe with your certificate

SignTool sign /fd SHA256 /a /f Test.pfx setup.exe

Retrieve OAuth 2.0 authorization code using JavaFX WebView


This post documents a snippet of code that can be added to Browser class in JavaFX WebView sample, to extract OAuth 2.0 authorization code.

Assuming you’ve configured WebView’s WebEngine to load the authorization URL, the authorization service will redirect you to the redirect_uri specified in the authorization URL, after a user logs in successfully. It will pass along the code parameter, that can be extracted as follows

OAUTH 2 with google-oauth-java-client


This post is a quick reference for running the dailymotion-cmdline-sample, a Java console sample app for the google-oauth-java-client OAUTH 2 library.

The sample app performs authorization code grant specified in the OAUTH 2 RFC, and receives user’s authorization code via an embedded Jetty HTTP server. That code is then exchanged for an access token.

Clone the google-oauth-java-client repo at GitHub

git clone git@github.com:google/google-oauth-java-client.git

Install Apache Maven if you don’t already have it. You’ll need Oracle’s JDK to use Maven and compile the sample app. On Mac OS X, Maven can be installed using Homebrew

brew install maven

Head into the cloned repo and compile

cd google-oauth-java-client
mvn compile

Head into the sample app folder and execute the sample app

cd samples/dailymotion-cmdline-sample
mvn -X exec:java -Dexec.mainClass="com.google.api.services.samples.dailymotion.cmdline.DailyMotionSample"

The first execution will fail. You’ll need to create a dailymotion.com developer account, which can be created at http://www.dailymotion.com/profile/developer. Create a new API key. The only value that really matters is the Callback URL which should be http://127.0.0.1:8080/Callback.

Enter your API credentials in rc/main/java/com/google/api/services/samples/dailymotion/cmdline/OAuth2ClientCredentials.java. Compile and exec again. The application should list your favorite videos if all goes well.

Dealing with .NET’s messy WebBrowser control


I’ve been trying hard to coax .NET’s WebBrowser control to log in using PingFederate federation server. I particularly don’t want to mess with the registry to change Internet Explorer’s browser emulation settings due to a single application. Something that with Android is amazingly simple, requires a lot of extra effort with .NET for the Desktop.

The WebBrowser control defaults to IE7 emulation as seen by the following User-Agent header, discovered using Fiddler.

User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729)

There’s a bug in the browser control that sends a trailing null character in POST data.

pf.username=xxx&pf.pass=xxx&pf.ok=clicked&pf.cancel=<NULL>

I had to extend the WebBrowser control, gain access to its internal ActiveX control, and use events of that control to modify the behavior just enough to be able to log in using PingFederate. The code that does that is reproduced below.

    public class ExtendedWebBrowser : WebBrowser
    {
        bool renavigating = false;

        public string UserAgent { get; set; }

        public delegate void BeforeNavigateDelegate(string url, ref bool cancel);

        public event BeforeNavigateDelegate HandleBeforeNavigate;

        public delegate void NavigateErrorDelegate(string url, ref bool cancel);

        public event NavigateErrorDelegate HandleNavigateError;

        public ExtendedWebBrowser()
        {
            DocumentCompleted += SetupBrowser;

            //this will cause SetupBrowser to run (we need a document object)
            Navigate("about:blank");
        }

        void SetupBrowser(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            DocumentCompleted -= SetupBrowser;
            SHDocVw.WebBrowser xBrowser = (SHDocVw.WebBrowser)ActiveXInstance;
            xBrowser.BeforeNavigate2 += BeforeNavigate;
            xBrowser.NavigateError += NavigateError;
        }

        private void NavigateError(object pDisp, ref object URL, ref object Frame, ref object StatusCode, ref bool Cancel)
        {
            if (HandleNavigateError != null)
                HandleNavigateError.Invoke((string)URL, ref Cancel);
        }

        void BeforeNavigate(object pDisp, ref object url, ref object flags, ref object targetFrameName,
            ref object postData, ref object headers, ref bool cancel)
        {
            if (renavigating)
            {
                renavigating = false;
                if (HandleBeforeNavigate != null)
                {
                    HandleBeforeNavigate.Invoke((string)url, ref cancel);
                }
            }
            else
            {
                byte[] pSrc = (byte[])postData;
                byte[] p = pSrc;

                if (pSrc != null && pSrc[pSrc.Length - 1] == 0)
                {
                    // remove trailing null from POST data
                    p = new byte[((byte[])postData).Length - 1];
                    Array.Copy(((byte[])postData), p, p.Length);
                    renavigating = true;
                }

                if (!string.IsNullOrEmpty(UserAgent))
                {
                    headers += string.Format("User-Agent: {0}\r\n", UserAgent);
                    renavigating = true;
                }

                if (renavigating)
                {
                    Navigate((string)url, (string)targetFrameName, p, (string)headers);
                    cancel = true;
                }
            }
        }
    }

The authorization code returned by PingFederate can be obtained by registering for HandleNavigateError event. Using the HandleBeforeNavigate event handler does not work, because it is not invoked when the browser control is redirected after a 302 Not Found response.

            extendedWebBrowser1.HandleNavigateError += delegate (string url,
                ref bool cancel)
            {
                cancel = ExtractAuthorizationCode(url);
            };

Tunnelblick OpenVPN client


If you need a decent OpenVPN client on a Mac, Tunnelblick is an excellent choice. Importing the OpenVPN client configuration file (.ovpn extension) is slightly more contrived than it should be, but if you follow the steps shown by Tunnelblick you should be good to go in no time.