HAProxy SSL end + client certificate validation + curl / java client

I would like to have SSL termination on HAProxy using my own self-signed certificates and verify client access using the client certificates you create.

I create server certificates (which are also CAs) like this:

openssl genrsa -out ca.key 1024
openssl req -new -key ca.key -out ca.csr
openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt

      

and

cat ca.crt ca.key > haproxy.pem

      

in HAProxy, I configure: bind *: 443 ssl crt / path / server.pem ca-file / path / ca.crt check required crt-ignore-err all

I create client certificates in a similar way:

openssl req -new -key client.key -out client.csr
openssl x509 -req -days 365 -in client.csr -signkey ca.key -out client.crt
cat client.crt client.key > client.pem

      

My logic is: I create a client key, a certificate signing request for it, and then I sign it with a CA (which is also a server certificate, so there is a simple chain that the server will recognize).

To test, first try with the server certificate as the client certificate:

curl https://my.service:443/ping -E ./haproxy.pem -k
pong

      

OK, it works. Now I will try with client certificate as client certificate:

curl https://my.service:443/ping -E ./client.pem -k
curl: (58) unable to set private key file: './client.pem' type PEM

      

My question is: 1) I would like to create a client certificate that this server will accpet and check it with curl. 2) I would like to import this certificate and CA into a new java store / store using keytool so that the java code (Jersey client) can access the same content.

I spent 2 days at 1/2. I'm pretty sure someone who has done this before could answer this in 5m. Or I hope. :)

Thank!

+3


source to share


1 answer


1.create client certificate

incorrect: openssl x509 -req -signkey

creates a self-signed certificate which by definition means that the key in the certificate (key question) is the public half of the same key whose private half signs the certificate, Documentation for cert (not req) case is clear that it replaces the key previously in the certificate , with the signature key. The document is -req

less clear, but it does the same; it puts in the cert the subject name from the CSR, as well as the issuer, and the key from -signkey

. You used a CSR containing the customer's name but -signkey

containing the CA key creating an unusable chimera.

right: to sign a "child" (not self-signed) certificate with x509

, use -CA

and possibly -CAkey

as described in the documentation https://www.openssl.org/docs/apps/x509.html#SIGNING-OPTIONS (or man [where] x509

in any Unix with openssl key installed). If there is or will be more than one child certificate for a given CA (its specific DN), either use the file-based serial number scheme to automatically and conveniently assign sequential serial numbers, or use -set_serial

to manually assign a unique sequential number (sequential is the easiest way to make a unique but if you prefer another way that's fine).

aside: for a self-signed CA (and server ?!) certificate, you don't need separate steps req -new

and x509 -req -signkey

, you can do it in one req -new -x509

, See the doc / manpage for req

. In fact, you do not need a separate step genrsa

, you req -newkey [-nodes] -x509

can do it. One note: in OpenSSL 1.0.0+ this generates a generic PKCS # 8 key file instead of the "old" PKCS # 1 format used genrsa

(s rsa

); all OpenSSL functions may accept either, but some other things may not. Specifically, I last checked (some time ago) the Wireshark option for decrypting SSL / TLS using the server key for akRSA (there are other options), only accepted by PKCS # 1, not PKCS # 8.

2. use in Java (Jersey). Note that any SSL / TLS client doing client authentication, including Java, needs both a certificate and a private key, and in most cases the certificate uses the "chain" or "intermediate" certificates which you require too. Some people (cough) Microsoft (cough) make you misunderstand and ignore this important distinction, but if you try to use only the certificate it won't work at all. On the other hand, only a certificate is required to record a trust, almost always only a root (CA) certificate, and usually only needs to have a certificate. Your situation where the same person is running a CA and the server and client (s) are somewhat unusual for PKC.

2a. maybe just converts to pkcs12. Java does not directly support opensl key formats, but both Java and openssl do support PKCS # 12 (as well as Microsoft, Mozilla, Apple, and possibly others). Since you combined client key and (sheet) cert in client.pem

do



openssl pkcs12 -export <client.pem -CA ca.crt [-name whatever] >client.p12
# if you use separate key,cert files see the doc about -in and -inkey

      

Java crypto (JCE and JSSE) can use this PKCS # 12 as a keystore if you can configure the "type" keystore type (like pkcs12). The default SSLSocketFactory

supports this, as well as other apps I've used, but I'm not using Jersey and don't know what it does here. PKCS # 12 is generally not supported for carrying "standalone" certificates (no private key), but in your case, the client's CA certificate is also the server's certificate, so it will work as your trust store as well; otherwise, you will need to import the CA server or server self-signed certificate (cert not privatekey only) into the JKS trust store (which can be the default trust store in JRE / lib / security / [jsse] cacerts).

2b. possibly further conversion to JKS. If Jersey cannot use PKCS # 12 directly, Java can convert it to JKS, which any sane Java code can use, e.g .:

keytool -importkeystore -srckeystore client.p12 -srcstoretype pkcs12 -destkeystore client.jks 

      

UPDATE 2018: Since this answer was written, Java PKCS12 support has increased, making it less necessary to convert to JKS. 8u60 released fall 2017 and still defaults to JKS keystore type, but as a special function (?) JKS type can actually read (though not write) PKCS12; see release notes and item keystore.type.compat

in file JRE/lib/security/java.security

. Java9, released 2017, creates a default PKCS12 keystore type that (as expected) reads and writes PKCS12, although explicit JKS no longer reads PKCS12. But if you need to convert from Java9 for some reason, now you need to specify -deststoretype jks

but no longer need to specify -srcstoretype pkcs12

.

+2


source







All Articles