Currently I am trying to setup a toy https server with socat I am doing the following:


cert() {
   openssl genrsa -out $1.key 2048
   openssl req -new -key $1.key -x509 -days 3653 -out $1.crt
   cat $1.key $1.crt > $1.pem
$ cert server &&  cert client

$ openssl dhparam -out dhparams.pem 2048 # see [1]
$ cat dhparams.pem >> server.pem

Socat SSL – SSL routines:SSL3_CHECK_CERT_AND_ALGORITHM:dh key too small

Then in terminal #1 I run:

$ socat ssl-l:1443,reuseaddr,fork,cert=server.pem,cafile=client.crt,verify=1 exec:'uptime'

in terminal #2 I run:

$ socat - ssl:localhost:1443,cert=client.pem,cafile=server.crt

And everything works as expected, I get the uptime, but if I do

$ curl --cert client.pem --cacert server.crt https://localhost:1443
curl: (51) SSL: unable to obtain common name from peer certificate

It fails.

I admit than my understanding of HTTPS is a bit shaky so I have several questions:

  1. Why it fails ?
  2. Why do we need to transfer the client certificate to the server ? This does not happen while I browse the net, or does it ?
  • 1
    For information: using self-signed certificates and then reusing the certificate as certificate authority on each peer is of course not what should be done. Anyway, if you take care to have CN=localhost when creating the certificates, it should work. Doing all you did was tested OK here once CN=localhost. socat 2.0.0-b9, curl 7.52.1, openssl 1.1.0f. for 2/ search on internet how it's working (eg: Certificateauthority)
    – A.B
    Jun 10, 2018 at 0:11
  • @A.B thanks for the comment ! If you write how to generate a certificate with appropriate CN, I'll accept the answer and upvote. Jun 11, 2018 at 18:31

2 Answers 2


Why it fails ?

The instructions you apparently followed are partly incorrect.

$ openssl req -new -key server.key -x509 -days 3653 -out server.crt
//     enter fields... (may all be empty when cert is only used privately)

The fields that req -new -x509 prompts for (at least with the 'standard' upstream config file) are used as the subject name in the created certificate (or the CSR without -x509). (For a selfsigned cert the issuer name is the same as the subject name so the same data also appears there.)

For HTTPS server, to establish that a connection reached the valid server and not an impostor, the server's cert must be valid per rfc5280 (signed by a trusted CA etc) AND the cert must be issued to the server named in the URL: either the Common Name field in the subject name in the cert must match the desired server, or the Subject Alternative Name extension (commonly abbreviated SAN and also called UCC by Microsoft or people influenced by Microsoft) must be present and contain an entry that does so. See rfc2818. That's why OpenSSL prompts for this field as:

Common Name (e.g. server FQDN or YOUR name) []:

because mostly people use URLs that identify the server by FQDN, although there are exceptions. So you need to answer that prompt with localhost. Officially SAN is preferred, and implemented by all 'real' CAs (Verisign Symantec Digicert, GoDaddy, etc) since about 2000, but doing SAN with OpenSSL is a little bit more work. There are many Qs already on Stack about SAN in OpenSSL; if you need and can't find them I'll dig some up from my notes. An exception is if you want to use Chrome/chromium: as of a few months ago it requires the cert have SAN (with the correct server name) and no longer accepts subject.CN. There are also Qs on this; ditto.

Note SSL/TLS based protocols other than HTTPS may differ, and an empty subject name may indeed be okay, e.g. FTPS SNMPS LDAPS.

Why do we need to transfer the client certificate to the server ? This does not happen while I browse the net, or does it ?

Do you really mean the net, or the web? Although the SSL/TLS protocol supports client authentication via client certificate, very few web servers on the secure (HTTPS) part of the web use this. Most web servers that need to authenticate their clients use HTTP-level methods -- as for example the options offered by Stack. This allows them to control the UI and make it consistent across all browsers, and provide instructions and help and support accordingly, while the UI for client certs is implemented by each browser or platform differently, and often requires some technical skill or at least intelligence and patience to use correctly, which most websites assume most users can't or at least won't do.

The few web servers that do use client cert generally require certs issued by a public CA and/or a trusted third-party (such as a government, or bank), or sometimes a CA run or controlled by the server itself. Using selfsigned client certs would indeed require users to provide their certs in advance -- and that provision process would have to be very secure, because anyone who could get a bogus cert accepted once would then be able to make fraudulent connections for years.

OTOH when you 'own' both ends, the server admin has an easy job identifying and trusting the client admin, and vice versa. AIUI OpenVPN key exchange uses this (SSL/TLS with selfsigned or maybe adhoc-CA certs).

Bonus answer: the above change should make the TLS layer of the connection work, but your setup still won't work as an HTTPS server, because the output of uptime is not a valid HTTP response. You need something that generates HTTP headers and content, in roughly the same way CGI 'pages' do under a real web server (for either HTTP or HTTPS).


The CommonName field is needed. It can be specified through the argument -subj:

$ openssl req -new -key $1.key -x509  -subj '/CN=localhost'  -out $1.cert

In addition, curl will expect an HTTP header:

$ printf "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 5\r\n\r\nhello" | socat -dd openssl-listen:8080,cert=server.pem,verify=0 -

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .