Search code examples
opensslssl-certificateclient-certificates

why "openssl pkcs12 -in keystore.p12 -out client-certificate.pem -clcerts -nokeys" need -nokeys


I am using openssl to generate client certificate and key which will be used in mutual authentication later with cUrl.

I am using the following command to generate client certificate.

openssl pkcs12 -in keystore.p12 -out client-certificate.pem -clcerts -nokeys

According to the documentation:

-clcerts only output client certificates.

My question is since -clcerts is only output client certificates why do we need to put nokeys again? Thanks


Solution

  • The usage one-liner isn't really complete, and the man page is not much better.

    -clcerts and -cacerts really mean: among the certificates in the input, include them in the output only if they respectively do or don't have a LocalKeyID, which usually is present for an EE cert and not for a CA cert (see below). Both of these have no effect on privatekeys, which are controlled only by -nokeys (and the options relating to encrypting any output key), so -clcerts without -nokeys would output both the privatekey and the with-LocalKeyID cert, but not any without-LocalKeyID cert(s). Since the file here is named client-certificate this is presumably not desired; if it was the file should be named something like client-key-and-cert.

    (Added) In detail: the X.509 PKI architecture defines two notionally-distinct categories: End-Entities (EEs) who use public-key cryptography for something(s) useful like Internet communications, email or messages, program or firmware signing, government documents like passports, etc and need certificates to do so; and Certificate Authorities (CAs), which collectively are trusted to, and do, issue certificates to EEs and themselves. Nowadays EE certs are not issued directly by a root (trusted) CA, except maybe in a limited organizational environment (or a testbench), but rather the EE certs are issued by 'intermediate' or 'subordinate' CAs which have their own certs issued either by the root or by a higher-level intermediate, possibly repeating before reaching a root. (In practice 1 intermediate is most common, 2 is fairly common, more is rare but possible.) To securely use a public key in this system you need the EE cert and the certs of (all) the intermediate CA(s) above it to, but not necessarily including, the root or '[trust] anchor', which form a 'chain' or 'path' that can be validated.

    EE and CA certs are usually distinguished by the BasicConstraints extension and the KeyUsage extension -- but not always; the PKIX standards are not applicable even to all Internet applications much less those outside, and even where they are applicable they aren't always fully obeyed. Many implementations of X.509 certificate handling were first created in the 1990s, before v3 of that standard added extensions, and can still operate without them. In any case openssl pkcs12 does not use this information.

    The (EE) owner of a cert generally needs both the matching privatekey plus the 'chain' cert(s) which it needs to provide to the relying parties (senders, recipients, users, etc). The PKCS12 (originally PFX) file format was designed primarily to handle this; conventionally a PKCS12 file contains a privatekey and matching cert, plus any needed chain cert(s). However, the specification is much more flexible, and it is possible to store almost any combination of privatekeys, certs, and sometimes other information. However, one convention is that when a privatekey and matching cert are present, both are marked by a LocalKeyID attribute with the same value. Certs put in the file that don't match a privatekey, often but not necessarily chain certs, do not have this attribute.

    Thus in the normal case a PKCS12 contains an EE key and cert plus chain (CA) cert(s), or the less common case of several pairs of EE key and cert plus chain (CA) cert(s) for all of them, -clcerts selects the EE cert(s) (even though many EEs aren't clients) and -cacerts selects the CA cert(s). However, if you have a PKCS12 containing the privatekey and matching cert for a CA and its chain cert(s) (the higher-level CA(s)), which is perfectly reasonable, -clcerts selects the CA cert that matches the privatekey and -cacerts selects the other CA cert(s). And if you have a PKCS12 containing 'extra' cert(s) that don't match a privatekey, -cacerts selects it(them) even if it is (they are) actually EE cert(s) (and -clcerts does not); for example Java does this for a truststore file when you directly trust EEs e.g. communication peers. It might have been clearer if Eric had spelled these options something like -owner-certs and -other-certs, but it's 25 years too late to change that.

    PS: this command isn't generating anything. The PKCS12 already contains the privatekey and certificate(s) and this command just extracts them into a different (possibly more useful) form. Whatever you did to generate the key and cert was done prior to this.