4

If someone have to transfer X.509 certificates in a single bundle, usually, it is recommended to pack them into PKCS#7. And content of PKCS#7 can be signed.

OpenSSL allows to pack certificates into PKCS#7 in the following way:

openssl crl2pkcs7 -nocrl -certfile domain.crt -certfile ca-chain.crt -out domain.p7b

As I understand from the man page of 'openssl crl2pkcs7', this PKCS#7 is signed:

The output file is a PKCS#7 signed data structure containing no signers and just certificates and an optional CRL.

A few questions here:

  1. What does 'containing no signers' mean?
  2. If the content (certificates) of PKCS#7 is not really signed, how can it be done using OpenSSL?
  3. How signature of PKCS#7 can be verified using OpenSSL considering that it was signed?

If I understand overall concept wrongly, please, clarify that.

tysonite
  • 429
  • 2
  • 5
  • 14

1 Answers1

7

TLDR: It's not actually signed. You do understand wrongly. To explain I'll start from the beginning.

PKCS#7, and its slightly modified and enhanced IETFized[1] form CMS Cryptographic Message Syntax https://www.rfc-editor.org/rfc/rfc3852 et pred et amici, is a standard that defines a whole series of different but similar messages for various cryptographic functions. One type of PKCS#7/CMS message is called SignedData and its original purpose, as you might reasonably guess, is to convey data with a digital signature, or for generality one or more signatures, for example a contract signed by both parties. PKCS#7 (mostly) uses public-key cryptography and needs/expects a way to properly match public-key values to entities like people and organizations and systems, called a PKI Public Key Intrastructure; in practice the PKI we use is X.509 Certificates issued by CAs Certificate Authorities which can revoke bad certificates using CRLs Certificate Revocation Lists (and nowadays also using OCSP, but that came after PKCS#7).

A SignedData actually consists of three main parts: the actual data in a structure named ContentInfo; a variable number of SignerInfo structures each containing one signature and some metadata including an identification of the certificate containing the public-key needed to verify the signature; and a variable number (maybe none) of certificates and/or CRLs that the recipient may need to determine and verify the (signing) public-keys or for any purpose. For generality the number of SignerInfo's, and thus signatures, may be zero, in which case the data is useless and is omitted.

Thus a SignedData with no data and no "signers" (zero SignerInfo structures), only certificates and/or CRLs, provided a standardized format to contain several related certificates and/or CRLs, at an early date when there was no other good standardized method for this. As a result it was widely adopted and became ubiquitous. This format is commonly identified by the extensions "p7b" and "p7c". See What's the difference between X.509 and PKCS#7 Certificate? .

So as to your questions: this format is a PKCS#7 or CMS structure of the type named SignedData, but it does not actually contain data or signature(s) on that data, it contains only certificates and/or CRLs. Because it isn't signed, it can't itself be verified.

Each certificate or CRL in itself is signed, using a signature specific to the cert/CRL format not a general data signature. This is independent of whether it is in a p7b or separate. Each (nonroot) cert or CRL after you extract it can be verified, if you have a valid chain of certs "above" it, and should be if you use it for anything. However all PKI signatures only propagate trust from a (usually small) set of trusted "roots" or "anchors" (such as Verisign, GoDaddy, etc but hopefully not DigiNotar) to an unboundedly large set of other entities (HTTPS or other SSL/TLS servers on the net, email senders in the world, program developers in the world, etc). Ultimately you decide what anchors to trust, or delegate that decision to someone (like Microsoft for Windows, Oracle for Java, Mozilla for Firefox, etc).

In OpenSSL all (AFAICS) operations that use certificates, and (optionally) CRLs, verify them, against a truststore of CA (root) certs that you can choose or default. You can also manually (re)verify a cert with the commandline verify utility; see https://www.openssl.org/docs/apps/verify.html . Other tools and programs will do something equivalent, but details vary some.

[1] for comparison, the Netscape protocol SSL Secure Sockets Layer was turned over to IETF where it was slightly modified and enhanced and renamed TLS Transport Layer Security. Although there are technical differences that do matter sometimes (like the recent POODLE vulnerability that affects SSL but is fixed in TLS, at least in correct implementations), for the most part SSL and TLS are functionally the same and people often just say SSL to mean both. Similarly PKCS#7 and CMS are so similar many people use either name for both.

Update 2/06 per comment: If you send a valid chain to a recipient who correctly validates the lowest (leaf) cert using that chain, that will prove whether the chain is valid as received.

  • If an attacker or fault modifies or deletes any (needed) cert or replaces one with an invalid or wrong cert, the received chain won't validate.
  • If an uneeded cert (either valid or not) is added it won't be detected, but won't harm security at the recipient either.
  • If you sent an unneeded cert (or several) and that uneeded cert(s) is modified, deleted or replaced it won't be detected, and won't harm.
  • If you omitted a needed cert and it is added (particularly an intermediate CA cert is likely to be widely known and available), the recipient won't detect the change, but security will be helped.
  • If there are multiple valid chains -- as is often the case with public CAs, especially now when many have recently upgraded to one or more of RSA-2k ECC SHA2 -- if you send one chain and it is modified to another chain that is also valid, the recipient won't detect the change. This is the only case I can see where the recipient can be harmed: if there are multiple valid chains but not equally "good" on some metric, like long-term sustainability, the recipient can be tricked into using a worse one.

PKCS#7/CMS can be nested. This is commonly used to both sign and encrypt (aka envelope) but other combinations are possible. If you really care the recipient get the exact chain (or other set) you send, not just a valid chain, you can put the p7b as the content of a second, outer SignedData message. In this case you have another choice: mostly for historical reasons PKCS#7/CMS can generate a "detached" signature, where the SignedData object does not actually contain the data, only the SignerInfo(s) and some metadata like the hash algorithm(s); in this case you must send both chunks of data in a way that the recipient can reliably connect them, e.g. Message12345.dat and Message12345.sig . Alternatively it can "embed" the data in the content slot of the SignedData message; this is probably simpler for your case. OpenSSL commandline can do this just by doing two steps, and much email software can handle the SignedData part or at least its S/MIME variants (which OpenSSL can also do), and the remaining p7b part can be handled by most if not all cert/security software.

RFC 4510 (and 2510) has lots of capabilities and options that I haven't dug through, and I'll readily believe there's something in there that does what you want, but I've never seen any implementation of it. You may well have to write -- and support -- the software at both (or all?) ends yourself.

dave_thompson_085
  • 9,759
  • 1
  • 24
  • 28
  • Dave, thank you for the answer. It becomes more clear. – tysonite Feb 03 '15 at 19:31
  • However, if I need to transfer some certificates (e.g. valid chain) from CA to other end-entity using PKCS#7, how can I be sure that the chain or/and EE's certificate was not altered? Can you propose other approaches than CMS/PKCS#7? I referred to my question number 2. For instance, I found out that CMPv2 (RFC 4210) protocol (as I understand, it is for on-line enrollments) allows to do that. It may (as per my understanding) sign the content of whole message containing chain of certificates. – tysonite Feb 03 '15 at 19:39
  • @tysonite see edit – dave_thompson_085 Feb 06 '15 at 12:09
  • For the last case where one valid chain is replaced with another valid one, if recipient want to prevent this case I guess he/she can just pin the root? – Franklin Yu Nov 16 '18 at 18:55
  • @FranklinYu: recipient certainly chooses (somehow) which root(s) it trusts to validate any chain against. But if it wants to choose 'must be the one the sender sent' and the message was altered, receiver can't be sure what the sender sent unless it is outer-signed (and that signature verifies). – dave_thompson_085 Nov 18 '18 at 16:07