Subject: [lamps] draft-ietf-lamps-samples: PKCS12 expertise needed (including objects for comparison)

From: Daniel Kahn Gillmor <[email-masked]>
Date: Thu, 29 Jul 2021 19:17:06 -0400

Hi folks--

We discussed draft-ietf-lamps-samples at the IETF 111 second LAMPS
session.

One concern is that the PKCS#12 objects in the current draft were
unimportable by MacOS's "Keychain Access" application.

Here's a screenshot of that failure, trying to ingest the DER-encoded
form of `bob.p12` from draft -06:

As the draft says, this PKCS#12 object is encrypted with a simple
3-letter password "bob".

However, Thunderbird's certificate manager *does* ingest the object
correctly, and can then export the associated objects as another PKCS#12
object, also encrypted with the password "bob".

This Thunderbird-laundered PKCS#12 object *is* ingestable by Keychain
Access for some reason.

I'm attaching here the original object as `bob.p12` and the
thunderbird-laundered version as `bob.laundered.p12`.  Both objects are
encoded in DER form.

Both objects *should* contain:

 - Bob's decryption secret key
 - Bob's corresponding encryption certificate
 - Bob's signing secret key
 - Bob's corresponding verification certificate
 - The intermediate CA certificate that permits verification from the
   ed25519 root CA

The secret keys in both PKCS#12 objects should be locked with the
password "bob".

Are we seeing a bug in Keychain Access?  Or is "bob.p12" somehow
malformed?  If "bob.p12" is malformed, is there a bug in Thunderbird
that it accepts it?

If anyone has any tooling that can make a clear and concise picture of
the differences between the objects (or can condense the screenfuls of
text that most detailed debuggers produce to highlight the specific
changes), that would be super useful.

          --dkg

---

From: Ryan Sleevi <[email-masked]>
Date: Thu, 29 Jul 2021 19:58:41 -0400

On Thu, Jul 29, 2021 at 7:17 PM Daniel Kahn Gillmor <[email-masked]>
wrote

> changes), that would be super useful.

 So I don't have a great answer for you here - I don't play much with
CMS/P7, but there's a pretty clear difference between laundered and
original that most tools (e.g. https://github.com/google/der-ascii,
https://lapo.it/asn1js/ , openssl asn1parse ) point out

In bob.p12, starting with offset 22, it goes
  CONSTRUCTED context-specific tag 0 (len 6049)
    OCTET STRING (len 6045)
       SEQUENCE (len 6041)

In bob.laundered.p12, starting with offset 18, it goes
  CONSTRUCTED context-specific tag 0 (len 6948)
    OCTET STRING (len 6944)
      OCTET STRING (len 6938)
        SEQUENCE (len 6936)

That is, there's a double OCTET STRING encoding here before the actual
content.

It's clear that in both of these tag-0 is part of the ContentInfo structure
(as it's part of a sequence with the previous value being the id-data OID).

id-data is an OCTET STRING type, with the interpretation left to the
application - https://datatracker.ietf.org/doc/html/rfc5652#section-4

The reason for the double encoding is because
https://datatracker.ietf.org/doc/html/rfc7292#section-4.1 - that is
   The content field of the authSafe shall, either
   directly (data case) or indirectly (signedData case), contain a BER-
   encoded value of type AuthenticatedSafe."

I'm not sure if this is your root cause, because I haven't poked to see
which of Apple's decoders and which of Thunderbirds' encoders are in play,
but it would _seem_ they're consistent in interpreting this as:

- 5652 requires that `id-data` be an OCTET STRING
- 7972 requires that the *contents* of that OCTET STRING be a BER-encoded
value of type AuthenticatedSafe, expressed as an OCTET STRING

Hence, "double" OCTET STRING encoded - the first to satisfy 5652, the
second to satisfy 7972.

At least, just judging from the first few bytes.

---

From: Russ Housley <[email-masked]>
Date: Fri, 30 Jul 2021 10:57:25 -0400

DKG:

in bob.p12, definite length encoding is used throughout, and the layers are:

	data (1 2 840 113549 1 7 1)
		encryptedData (1 2 840 113549 1 7 6)
			data (1 2 840 113549 1 7 1)
				pbeWithSHAAnd3-KeyTripleDES-CBC (1 2 840 113549 1 12 1 3)
		encryptedData (1 2 840 113549 1 7 6)
			data (1 2 840 113549 1 7 1)
				pbeWithSHAAnd3-KeyTripleDES-CBC (1 2 840 113549 1 12 1 3)
		encryptedData (1 2 840 113549 1 7 6)
			data (1 2 840 113549 1 7 1)
				pbeWithSHAAnd3-KeyTripleDES-CBC (1 2 840 113549 1 12 1 3)
		data (1 2 840 113549 1 7 1)
			pkcs-12-pkcs-8ShroudedKeyBag (1 2 840 113549 1 12 10 1 2)
				pbeWithSHAAnd3-KeyTripleDES-CBC (1 2 840 113549 1 12 1 3)
			friendlyName (for PKCS #12) (1 2 840 113549 1 9 20)
			localKeyID (for PKCS #12) (1 2 840 113549 1 9 21)
		data (1 2 840 113549 1 7 1)
			pkcs-12-pkcs-8ShroudedKeyBag (1 2 840 113549 1 12 10 1 2)
				pbeWithSHAAnd3-KeyTripleDES-CBC (1 2 840 113549 1 12 1 3)
			friendlyName (for PKCS #12) (1 2 840 113549 1 9 20)
			localKeyID (for PKCS #12) (1 2 840 113549 1 9 21)

in bob.laundered.p12, indefinite length encoding is used in the outermost layers, and the layers are:

	data (1 2 840 113549 1 7 1)
		OCTET STRING
			data (1 2 840 113549 1 7 1)
				OCTET STRING
					pkcs-12-pkcs-8ShroudedKeyBag (1 2 840 113549 1 12 10 1 2)
						pbeWithSHAAnd3-KeyTripleDES-CBC (1 2 840 113549 1 12 1 3)
						friendlyName (for PKCS #12) (1 2 840 113549 1 9 20)
						localKeyID (for PKCS #12) (1 2 840 113549 1 9 21)
			encryptedData (1 2 840 113549 1 7 6)
				data (1 2 840 113549 1 7 1)
					pbeWithSHAAnd40BitRC2-CBC (1 2 840 113549 1 12 1 6)
			data (1 2 840 113549 1 7 1)
				OCTET STRING
					pkcs-12-pkcs-8ShroudedKeyBag (1 2 840 113549 1 12 10 1 2)
						pbeWithSHAAnd3-KeyTripleDES-CBC (1 2 840 113549 1 12 1 3)
						friendlyName (for PKCS #12) (1 2 840 113549 1 9 20)
						localKeyID (for PKCS #12) (1 2 840 113549 1 9 21)
			encryptedData (1 2 840 113549 1 7 6)
				data (1 2 840 113549 1 7 1)
					pbeWithSHAAnd40BitRC2-CBC (1 2 840 113549 1 12 1 6)

40-bit RC2? Really?

Russ

---

From: Daniel Kahn Gillmor <[email-masked]>
Date: Sat, 31 Jul 2021 01:19:43 -0400

> 40-bit RC2? Really?

hey, i just clicked the buttons, i didn't set any knobs!

afaict, it looks to me like the 40-bit RC2 in bob.laundered.p12 is
wrapping the certificates themselves, not the associated secret keys,
which i think are inside the pkcs-12-pkcs-8ShroudedKeyBag objects, which
are protected with pbeWithSHAAnd3-KeyTripleDES-CBC instead?

hm, looks like bob.laundered.p12 is also missing the cross-signed
intermediate CA cert, but that is probably due to operator error when i
was trying to figure out what to select in Thunderbird's certificate
manager to make the exported p12 object contain the right keys.

Seems to me like there's no need to encrypt any of the public objects
(certificates) in a PKCS12 file, and 40-bit RC2 doesn't seem that much
worse than cleartext.

do folks here think it's a bug that Keychain Access isn't capable of
reading bob.p12, but is capable of reading bob.laundered.p12?  or is
bob.p12 actually malformed in some way?

I confess i don't understand the definite length encoding vs. indefinite
encoding question.  are these both acceptable PKCS#12 structures?

     --dkg

---

From: Ryan Sleevi <[email-masked]>
Date: Sat, 31 Jul 2021 21:14:36 -0400

> bob.p12 actually malformed in some way?

It’s PKCS#12. There is very little interoperability on the market in
general, as it is a hell format that is functionally impossible to
implement securely, and so no vendor particularly wants to touch.

I realize that sounds like my usual hyperbole, but it truly is a pernicious
format. In Mozilla NSS, it uses what is known as the “legacy” decoder,
because of the need to support BER. The “legacy” decoder is so named
because it was, and is, a security tirefire, and the whole system was
replaced everywhere in NSS - except the CMS and P12 systems, because unlike
other places, Mozilla didn’t feel they could restrict to DER only and
remain compatible.

For Apple, there’s actually a shared history: the first CMS decoder on
macOS systems began as a port of the NSS libraries. This is why, for
example, it is speculated that the FBI was able to gain access to the San
Bernardino shooters’ phones: by exploiting a bug in the legacy decoder from
NSS that had, incidentally, been ported to macOS/iOS [1].

When folks say PKCS#12 is not a place of honor [2] [3] [4], they truly mean
nothing valued is there.

Again, I realize this sounds hyperbolic, but I also do it to highlight that
there’s very little interoperability in the deployed software, in part
because it’s impossible to maintain. Since that bug, I believe Apple has
rewritten their CMS and PKCS#12 parsers twice; although rewritten may be a
bit of a stretch, as it’s more like there are three different parsers
depending on which product you’re using.

> encoding question.  are these both acceptable PKCS#12 structures?

Indefinite length means BER: the format from which a thousand security bugs
bloom, because the message size is generally not known before hand, and so
you constantly end up running past the end of the message, onto the stack,
and making everyone sad along the way. Definite length may be BER or may be
DER: it means you actually send the length before the data.

The implementation details I mentioned above play into this: you should try
to always use DER, for BER is the path of doom. That said, implementations
that have an ancestral heritage to NSS, with its unmaintained (and
insecure) BER parser (not to be confused with its DER parser for certs and
things), will still prefer to encode in BER. I realize saying “use DER”
doesn’t get you closer to “interoperable PKCS#12 file”, your end goal, but
that’s mostly because many folks gave up on “interoperable PKCS#12” ages
ago, and have accepted “if it works, it works, if it doesn’t, try doing
something different.”

[1]
https://twitter.com/zhuowei/status/1382475494084476928
[2]
https://en.wikipedia.org/wiki/Long-time_nuclear_waste_warning_messages#Message
[3]
https://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html
[4]
https://unmitigatedrisk.com/?p=543