0

I generated a certificate in the directory of my Haskell app:

openssl genrsa -out key.pem 2048
openssl req -new -key key.pem -out certificate.csr
openssl x509 -req -in certificate.csr -signkey key.pem -out certificate.pem

and then I ran my app:

import Network.Wai
import Network.Wai.Handler.Warp
import Servant
import Network.Wai.Handler.WarpTLS

startApp :: IO ()
startApp = do
  let port = 3345
  let tls = tlsSettings "certificate.csr" "key.pem"
  runTLS tls (setPort port defaultSettings) app

And then went to https://localhost:3345 and I got an error "empty certificate chain"

What's wrong with it? Maybe I've put my certificate somewhere such as "/opt/...."?

For now all 3 files are in the root directory of my application: key.pem, certificate.csr and certificate.pem.

UPDATE:

It's arch linux, whereas on hosting I have Ubuntu, therefore I'll need a solution for both.

This certificate is self-signed, whereas on hosting it's issued by let's encrypt.

I've changed a code a bit: "csr" to pem:

let tls = tlsSettings "certificate.pem" "key.pem"
runTLS tls (setPort port defaultSettings) app

Here's another error:

    $ curl -v https://localhost:3345
* Rebuilt URL to: https://localhost:3345/
*   Trying ::1...
* connect to ::1 port 3345 failed: Connection refused
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3345 (#0)
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS alert, Server hello (2):
* SSL certificate problem: self signed certificate
* Closing connection 0
* TLSv1.2 (OUT), TLS alert, Client hello (1):
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.haxx.se/docs/sslcerts.html

curl performs SSL certificate verification by default, using a "bundle"
 of Certificate Authority (CA) public keys (CA certs). If the default
 bundle file isn't adequate, you can specify an alternate file
 using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
 the bundle, the certificate verification probably failed due to a
 problem with the certificate (it might be expired, or the name might
 not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
 the -k (or --insecure) option.
Jushiti
  • 165
  • 1
  • 10
  • do you get the error in your application or is this the browser informing you that the certificate might be untrusted? - Because if I check the [code](https://hackage.haskell.org/package/tls-1.3.3/docs/src/Network-TLS-Credentials.html#credentialLoadX509Chain) that should be used here (well I only had a quick glance and the current docs are not on *hackage* so I'm not sure at all) - it seems that the only error you should get is `"no keys found"` - can you post the actual output? – Random Dev Apr 18 '16 at 04:39
  • You may want to try [MouseBox](https://github.com/shimmercat/mousebox) .... – dsign Apr 18 '16 at 05:00
  • @Carsten, it's the output of my application, there's nothing more there. – Jushiti Apr 18 '16 at 06:44
  • @dsign, why on Earth I'd take a solution which more difficult and unknown? Instead of fixing my error, I'd take that library and encounter another error who no body would know how to fix? – Jushiti Apr 18 '16 at 06:45
  • @Jushiti: How did you "went to https://…"? Using a browser? Try `curl` or `wget` with verbose information instead. Where did you get the error? In the client? In the server? Note that several systems expect you to update their certificate store, for example Ubuntu wants them at `/usr/local/share/ca-certificates/` and places them with `sudo update-ca-certificates` at the correct place afterwards. Either way, at the moment, you need to provide a little bit more information. – Zeta Apr 18 '16 at 07:25
  • @Carsten, updated. – Jushiti Apr 18 '16 at 07:57
  • @Jushiti It's a tool that I made exactly to solve that problem. And it is part of a [commercial solution](https://www.shimmercat.com/), we are on it for the long run. Plus, it has a standalone executable, it is not just a library. – dsign Apr 18 '16 at 08:00
  • @dsign, so instead of understanding how to do that on a lower level, I'd have to use your abstraction and depend on it? – Jushiti Apr 18 '16 at 08:06
  • well to me it looks as if your system/browser rejects the certificate (see Zetas comment for a possible fix) - sorry that I missed the `csr/pem` problem in the first place - anyway it should work - locally you don't need it so I would just use it on the server with the actual certificate – Random Dev Apr 18 '16 at 08:06
  • BTW: please stop complaining about @dsign s comment - it's probably both viable and the right thing to do - in the end you are at a point where it's no Haskell/programming issue but hard IT stuff ;) – Random Dev Apr 18 '16 at 08:07
  • @Carsten, on a server I have 4 files: cert1.pem, chain1.pem, fullchain1.pem and privkey1.pem. Which one is my key and certificate I should I use in Haskell, could you tell me? – Jushiti Apr 18 '16 at 08:09
  • @Jushiti: Wait a second. Could you please show how you generated the certificate? It seems like you didn't fill in the FQDN (fully qualified domain name, also called *common name*). Without one, it's not clear to which domain the certificate actually belongs and will get rejected. – Zeta Apr 18 '16 at 08:17
  • I would go with `cert1.pem` for the certificate and `privkey1.pem` for the key – Random Dev Apr 18 '16 at 08:20
  • @Jushiti If you want to understand things at a lower level, this [answer may help you](http://security.stackexchange.com/questions/20803/how-does-ssl-tls-work). This [guide](https://www.thawte.com/resources/getting-started/how-ssl-works/) is also good. – dsign Apr 18 '16 at 08:20
  • @Zeta, all empty. Where should've I specified localhost? – Jushiti Apr 18 '16 at 08:34
  • @Zeta, with localhost for FQDN the error is still the same, maybe it depends on a port also? – Jushiti Apr 18 '16 at 08:44

1 Answers1

3

TL;DR: Handling certificates is hard. Use the self-signed .pem file (and the key) and add security exceptions to your browser or your operating system. The .csr file isn't something you can use. The server is fine (except for the .csr file), but you will end up with security warnings till you get your key signed by a CA (which isn't possible for local domain names).


What's wrong with it?

The server is (almost) fine. However, you want to send the .pem file. The .csr is a request for signing your certificate by a certificate authority (CA). A CA needs to get trusted by the user or another CA (that's trusted by the user). Let's have a look at your original commands:

openssl genrsa -out key.pem 2048

This will generate the private key, which will get used for the TLS handshake and other operations.

openssl req -new -key key.pem -out certificate.csr

This will generate the mentioned certificate sigining request. You would send this request to a CA, which checks your identity. For example, they would check whether the FQDN actually is yours. Otherwise, you could ask for a certificate for stackoverflow.com and use a MITM attack. This also concludes that you cannot ask a (non-local) CA for a certificate on a local name, like localhost or hostname.local.domain.name.

openssl x509 -req -in certificate.csr -signkey key.pem -out certificate.pem

This will take the original certificate request, use your own key to sign it, and generate a certificate (certificate.pem). Usually, this certificate contains a CA chain, e.g. who signed the CA's certificate, who signed the certificate of the one that signed the CA's certificate and so on, till we end up at a root certificate.

So, all you have to do is to use that certificate together with your private key. This will lead to security warnings though, since you cannot prove your own identity. That's why you need --insecure in curl and a security exception in most browsers. That aside, it will work. Note that the server doesn't know that its certificate is self-signed. It's just using two files to initiate the communication with the client.

Community
  • 1
  • 1
Zeta
  • 103,620
  • 13
  • 194
  • 236