0

I would like your help identifying why step 5 (near the end) is necessary.

I have a working set of steps that create a keystore.ks with a chain that includes a local Certificate Authority cert. HTTPS communication between the master tomcat (the client) and the slave tomcat (the server) work; which is great, except I am concerned that I'm including to much in the slave keystore.ks.

The master tomcat (the client) has a truststore.ks which has a single entry which was created this way:

1) Create a new private key and a new certificate (CA) file (new_ca.pem):

openssl req -x509 -passout pass:mykeypassword -new -config caConfig.txt -days 7300 
-out new_ca.pem -keyout new_ca_pk.pem

2) Import into the truststore.ks

keytool -importcert -noprompt -alias myrootca -keypass mykeypassword 
-keystore truststore.ks -storepass changeit -storetype jks -file new_ca.pem

The slave tomcat (the server) has a keystore.ks with a single entry created this way:

1) Generate a certificate and private key pair:

keytool -genkey -noprompt -dname "CN=10.93.101.33, C=US, O=MyCompany, OU=MyCompany 
Manufacturing, ST=MA, L=MyTown" -validity 7000 -alias tomcat -keypass aPassword 
-keystore keystore.ks -storepass aPassword

2) Create a certificate signing request

keytool -certreq -alias tomcat -file 10.93.101.33.csr -keypass aPassword  
-keystore keystore.ks -storepass aPassword

3) Sign the CSR

openssl ca -batch -passin pass:mykeypassword -config caConfig.txt -days 7000 
-in 10.93.101.33.csr -out 10.93.101.33.crt

4) Convert to PEM format

openssl x509 -in 10.93.101.33.crt -out 10.93.101.33.crt -outform PEM

5) Concatenate the files

cat 10.93.101.33.crt new_ca.pem > 10.93.101.33.chain

6) Update keystore with the full certificate chain

keytool -import -alias tomcat -noprompt -file 10.93.101.33.chain -keypass aPassword 
-keystore keystore.ks -storepass aPassword

The above steps DO create a working system. The client tomcat can communicate with the server tomcat via https without the issues of trust. I'm concerned with a couple of things, why do I need to add the CA cert to the server tomcat's keystore? Lastly, is there an easier way of doing this?

Thanks for your time.

---------- EDIT --------------

The complete caConfig.txt:

HOME            = /home/hammer/hmweb/CertificateGenerator/CACertificate
RANDFILE        = $ENV::HOME/.rnd

dir = $HOME

[ ca ]
default_ca = CA_default

[ CA_default ]
serial = $dir/serial.txt
database = $dir/index.txt
unique_subject = no
new_certs_dir = $dir/newcerts
certificate = $dir/new_ca.pem
private_key = $dir/cakey.pem
crl = $dir/crl.pem
default_days = 7300
default_crl_days = 3650         # how long before next CRL
default_md = sha1
preserve = no
email_in_dn = no
policy = policy_match

x509_extensions = usr_cert

# Comment out the following two lines for the "traditional"
# (and highly broken) format.
name_opt    = ca_default        # Subject Name options
cert_opt    = ca_default        # Certificate field options

# For the CA policy
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional

# For the 'anything' policy
# At this point in time, you must list all acceptable 'object'
# types.
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional

####################################################################
[ req ]
default_bits = 2048
default_keyfile = cert.key
string_mask = MASK:0x2002
utf8 = yes
prompt = no
distinguished_name = req_distinguished_name
policy = policy_anything

x509_extensions = v3_ca # The extensions to add to the self signed cert

####################################################################

[ usr_cert ]

# These extensions are added when 'ca' signs a request.

# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.

basicConstraints=CA:FALSE


# This will be displayed in Netscape's comment listbox.
nsComment           = "OpenSSL Generated Certificate"

# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer:always

[ req_distinguished_name ]
countryName         = US
stateOrProvinceName     = MA
localityName            = MyTown
0.organizationName      = MyCompany
organizationalUnitName      = MyCompany Manufacturing
commonName          = !!COMMON_NAME_REPLACE_ME!!

[ v3_req ]

# Extensions to add to a certificate request

basicConstraints = CA:FALSE
subjectKeyIdentifier = hash

[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = CA:true
D-Klotz
  • 1,973
  • 1
  • 15
  • 37
  • Just wondering whether you had any problems with your `policy_match` requirement (depending on your policy), because the encoding of some of the names generated by `keytool` might be different from OpenSSL (even if the letters appear to be the same). It's also generally better to order your RDNs hierarchically, for Java "CN=10.93.101.33,OU=MyCompany Manufacturing,O=MyCompany,L=MyTown,ST=MA,C=US", for OpenSSL (depending on the command) "/C=US/ST=MA/L=MyTown/..." – Bruno Mar 11 '14 at 11:15
  • @Bruno No, I didn't have an error, but let me update the question showing what I used. – D-Klotz Mar 11 '14 at 14:37

2 Answers2

1

You only need step 5 if a chain is required. (This is a very similar problem to what's described for a client-certificate chain in this question.)

The minimal requirement is to include the chain of certificate up to, but excluding, the CA that can be expected to be one of the trust anchors (truststore) of the remote party. Your step 5 isn't necessary if you can expect the remote party to trust the CA that issued the certificate itself (which is indeed the case according to the way you've built the client truststore). Needless to say that if you skip step 5, you'll still need step 6 with the certificate file (i.e. chain of length 1) instead of the concatenated chain file.

For example:

  1. Assuming you have: "Server Cert" issued by "Root CA"

    Either the client has the "Root CA", or it doesn't. In both cases, there's no point sending the "Root CA", since it won't give additional information to the client. A client that trusts "Root CA" will be able to build a certificate path from "Server Cert"; a client that doesn't simply won't be able to trust that server cert anyway.

  2. Assuming you have: "Server Cert" issued by "Intermediate CA 1" issued by "Intermediate CA 2" issued by "Root CA"

    • If the client can be expected to trust "Intermediate CA 1", just present "Server Cert".
    • If the client can be expected to trust "Intermediate CA 2", you'll need to present a chain with "Server Cert" and "Intermediate CA 1".
    • If the client can be expected to trust "Root CA", you'll need to present a chain with "Server Cert", "Intermediate CA 1" and "Intermediate CA 2".

Of course, example 1 is merely a special case of example 2. This is why some people are reluctant to use the expression "Root CA": whether a CA cert sits at the top of a chain and is self-signed is barely relevant when constructing the chain of trust. All you need is the remote party to trust in advance a CA certificate that will be able to verify that last certificate in the chain you present (whether that chain is of length 1 or more).

Community
  • 1
  • 1
Bruno
  • 119,590
  • 31
  • 270
  • 376
  • Hi Bruno. This is a continuation of a question/answer that you helped with a few days ago. In that case I had used XCA to build the system and got it working. Here I'm attempting to use just command line tools. I did get it to work, but if I do not do step 5, the communications fail. I'll have to repeat the experiment to verify what type of error it was. – D-Klotz Mar 10 '14 at 02:26
  • If you skip step 5, you'll need step 6 with the cert file instead of the chain. This being said, I can't see anything in your commands or config where you set the SAN for the IP address, which you'll also need when using IP addresses instead of names (for the hostname verifier). – Bruno Mar 10 '14 at 02:40
  • ah, but in my case I changed the host name verifier code to always return true within the server. Yes I know that is a security hole. – D-Klotz Mar 10 '14 at 03:15
  • Sorry, you're right, if you skip step 5 when using `keytool`, you would at least need to import your CA cert (in a different alias) into your keystore (exactly the same way as you've done it with the trust store), otherwise, `keytool` will refuse to re-import the certificate ("*Failed to establish chain from reply*"). This is only a `keytool` requirement. You could bypass that if handling the keystore programmatically or via other tools. If I were you, I'd use PKCS#12 file straight from OpenSSL (no need for `keytool` except for the truststore), you would avoid other conversion oddities. – Bruno Mar 10 '14 at 15:23
0

In step 5 you are just putting CA cert and server cert into a single file and in the step 6 you are importing both certs into the keystore. AFAIK CA cert must be present in the keystore when you are importing end-entity cert (server cert in your case) so the origin of the end-entity cert can be verified.

Few days ago there was a similar question here on SO: guy had a problem importing server cert into the keystore because he was missing CA cert. He imported CA first and then everything worked. Based on that I believe step 5 is necessary but you can easily try it yourself: just skip step 5 and try to import 10.93.101.33.crt in step 6.

As far as the easier way of preparing a keystore is the question if you prefer GUI based tools I really recommend you to check out XCA for CA management and Portecle for a keystore management.

Community
  • 1
  • 1
jariq
  • 11,681
  • 3
  • 33
  • 52
  • The question you link to is a different problem, it's not so much about the chain presented by the server as it is about having the client trust CA certificate capable of verifying that chain (only length 1 in that question, since there's no intermediate CAs). You actually don't need to send the CA certificates that are trusted by the remote party in the chain: you only need to send those that are not, hoping that one of them will be issued by one of the CAs trusted by the remote party. – Bruno Mar 09 '14 at 21:33
  • I agree with you on "you don't need to send the CA certificates that are trusted by the remote party in the chain" in general but if the step 5 is skipped than you receive "keytool error: java.lang.Exception: Failed to establish chain from reply" in step 6 which is exactly the same error as was described in the question I've linked. – jariq Mar 09 '14 at 22:01
  • There's no suggestion of an error being thrown in this question. The question is about what to put in the chain presented by the server (in its keystore), not what to put in the client trust store (what your answer to the other question was about). In fact, since there's no intermediate cert in this example, including the CA cert or not in the server chain will make no difference. Of course, the CA will need to be in the client's truststore (either way). – Bruno Mar 09 '14 at 22:38
  • In my case if I do skip step 5, the resulting communications fail. – D-Klotz Mar 10 '14 at 02:24