Search code examples
javascalasslhttps

How do I correctly store the certificate chain (rootCA -> server csr) into a keystore in Scala, with self-signed certificates?


I have a single rootCA certificate in the resource folder (along with its private key) of my project.

When the software starts, it initialises the SSLManager object, which in turn:

  • Loads the rootCA into an x509Certificate
  • Loads the rootCA private key
  • Generates a server keypair and certificate
  • Signs the certificate using the rootCA

I would like to store the rootCA and server certificate into a keystore, that I can later use to setup an SSLContext, and for more secure storage.

I know how to store a single keypair/certificate into a keystore, but how would I correctly go about this for a chain?

I presume:

keyStore.setKeyEntry(ALIAS, privateKey, password.toCharArray, Array(rootCA, serverCert))

However, if true, which private key do I use (rootCA vs server)?

A full example would be much appreciated.


Solution

  • I presume: keyStore.setKeyEntry(ALIAS, privateKey, password.toCharArray, Array(rootCA, serverCert))

    Close

    However, if true, which private key do I use (rootCA vs server)?

    Use the privatekey of the server, and the cert-array must have the server cert FIRST, followed by its chain cert(s) preferably in upward sequence but possibly omitting the root.

    This is because JSSE will send this cert-array as the cert-chain in the SSL/TLS handshake. The original standards required that the cert-chain sent by a server begin with the server cert, followed the chain CA certs in strict upward sequence -- "Each following certificate must directly certify the one preceding it." In practice, quite a few servers due to miscoding or misconfiguration got certs after the first out of order, and since they can be sorted out given only the first one is correct, SSL/TLS clients were coded to tolerate this; the latest standard, RFC8446 for TLS1.3, now recommends support for "potentially extraneous certificates and arbitrary orderings" EXCEPT that "the end-entity cert[] MUST be first".

    In addition, all standards have allowed the root cert to be omitted from the transmitted chain, because it isn't needed; a client can safely validate the cert and chain, and thus the server's identity, only using a root cert (or possibly a nonroot anchor) already configured/stored local to that client (for Java typically in JRE/lib/security/cacerts, for other software in comparable ways), so having the server send another copy is a waste of bandwidth -- though a fairly small one. Java keytool does not like to create a PrivateKeyEntry with a chain that omits the root, but code you write can, and JSSE will happily send either.

    For your simple case, this means an array of (servercert, rootcacert) or optionally just (servercert)