I like using the Indy components when working with all sorts of internet things, but unfortunately documentation is scarce at best. So I spend hours on hours trying to find some hint as how to do things. Just lately I needed to get SSL working with my REST server for a specific service I offer.
Now, to some people, SSL comes easy. It doesn’t for me. To me, all things cryptic is, well, cryptic.
The core of my challenge
I have set up a web site using HTML, CSS and jQuery. No templates, no nothing, just plain old web fidgeting. This web site has some services that authenticates, populates tables and forms, stores data etc by interacting with my REST service made completely with Delphi.
Now, my web site and service are at, let’s say www.mywebsite.com and my REST service are at rest.myservershack.com on port 1234. Let’s say… None of these URLs actually work (to my knowledge).
So having dealt with all the cross domain stuff, the AJAX requests and all the javascript and pixel pushing, I arrived at the issue of HTTPS. How will I get that to work on my web site, but also on my rest server.
The solution
The first part, getting the web site under HTTPS was fairly simple. As it turns out, my service provider where my web site is located actually offers a Let’s Encrypt option, still under beta but anyway. It seems to work nicely. I just had to activate that service and a few minutes later my web site was up and running under HTTPS.
The next step was to be able to communicate with my REST server using HTTPS. I realized that I cannot have a web site under HTTPS talking to a rest server under HTTP. I got all kinds of warnings trying to accomplish that, so that was out of the question.
So I tried creating my own certificates. And while self signed certificates is OK to use internally (as I understand it from my readings on the Internet), it isn’t OK on public services. And you still get a lot of warnings. And it’s a bitch to get all the certificates up and running.
So I went to Go Daddy and purchased an SSL certificate. It cost me 50-60 bucks and was pretty easy to get up and running.
Creating the CSR
You will have to create a CSR (certificate signing request), and I think that’ll you’ll have to do that wherever you purchase your certificate. Or if you create one yourself on Let’s Encrypt (where it’s free, but you need to create everything yourself as I understand it).
I created a private key and a CSR using OpenSSL as described below.
- If you don’t have OpenSSL installed, google it and install it
- Open a CMD in Administrator mode
- Issue the following commands
c:\OpenSSL\bin\openssl OpenSSL> genrsa -out <anIntelligentName>.private.key 2048 OpenSSL> req -new -key <anIntelligentName>.private.key -out <anIntelligentName>.csr.txt
The third command, that ends with csr.txt, will create a CSR file. But first it’ll ask you a bunch of things. Just fill the information in (it’s like country code, region, email etc). The only thing to know is that (at least with GoDaddy) you need to add the exact url that you plan to use for your REST service under the Common Name question, like so:
Common Name (e.g. server FQDN or YOUR name) []:<yourRESTurl>
After that, you just need to copy the contents of the CSR file into the edit in the Go Daddy SSL certificate configuration tool. All that is explained by GoDaddy as the process progresses.
Next step is to proof that you control your domain, and there are a couple of ways you can do that with GoDaddy. They’re all described by GoDaddy, but the gist is that you can either create a TXT dns entry with a code GoDaddy provides or you can create an .html file with that code in it and place it on a special place on your web site. For some reason this place is
http://<yourWebSite>/.well-known/pki-validation/godaddy.html
Then all you have to do is click on the validation button on your GoDaddy account and, voila, your certificate is created and can be downloaded.
Adding the certificate to your REST server
There are a few ways you can set up a REST server with Delphi. I use the TIdHTTPWebBrokerBridge and TIdServerIOHandlerSSLOpenSSL to accomplish this. I won’t go into details here, but I think I’ve done a pretty nifty framework for this. If you’re interested, please let me know. Perhaps it can be another blog.
But in regards to getting SSL to work, this is what you need to do:
IdOpenSSLSetLibPath( ExePath ); LIOHandleSSL := TIdServerIOHandlerSSLOpenSSL.Create( FServer ); LIOHandleSSL.SSLOptions.CertFile := 'gd_bundle-g2-g1.crt'; LIOHandleSSL.SSLOptions.RootCertFile := '10ec713efc41838d.crt'; LIOHandleSSL.SSLOptions.KeyFile := '<anIntelligentName>.private.key'; LIOHandleSSL.SSLOptions.SSLVersions := [ TIdSSLVersion.sslvTLSv1, TIdSSLVersion.sslvTLSv1_1, TIdSSLVersion.sslvTLSv1_2, TIdSSLVersion.sslvSSLv2, TIdSSLVersion.sslvSSLv23, TIdSSLVersion.sslvSSLv3 ]; LIOHandleSSL.OnVerifyPeer := OnVerifyPeer; FServer.IOHandler := LIOHandleSSL;
When you download your certificate from GoDaddy you get a zip file with two certificates in it. These are used with the CertFile and RootCertFile properties. The KeyFile is the private key file that you created in the first step as you created your CSR file above.
Now, I won’t go into detail about these files, partly because this article is getting rather long, but mostly because I just don’t know. I guess the 10ec… file is the root certificate for GoDaddy and the gd_bundle one is the certificate. Or the other way around. But this configuration seems to work. Yes, crypto magic… But for once it’s in my favour.
Oh, the OnVerifyPeer function just returns ‘OK’. It probably should verify the correctness of the certificates somehow.