[krbdev.mit.edu #7889] PKINIT use of OpenSSL OID table is not thread-safe or application-friendly
Greg Hudson via RT
rt-comment at krbdev.mit.edu
Sun Mar 23 12:57:26 EDT 2014
OpenSSL contains two global internal tables which map between object
identifiers and integer identifiers (called NIDs) for application
convenience. (These tables also map OIDs to "short names" and "long
names" but that is unimportant to this bug.) The first table is
immutable and maps frequently used OIDs to to API constants such as
NID_sha1. The second table is a mutable and can be populated by callers
using OBJ_create or OBJ_add_object. Query functions such as OBJ_nid2obj
and OBJ_sn2nid consult the mutable table first, then the immutable
table. OBJ_cleanup frees and resets the mutable table. As of this
writing, the mutable table does not appear to be protected by any mutex
calls, even if mutex callbacks are registered by the OpenSSL caller.
On initialization, PKINIT adds nine PKINIT-related OIDs to the mutable
table if they don't have pre-existing mappings. On cleanup, PKINIT
calls OBJ_cleanup. A global counter in the PKINIT code (not protected
by any mutex) tries to prevent PKINIT from removing its own OIDs from
the mutable table when another context has the PKINIT module loaded.
In addition, pkinit_pkcs7type2oid registers 1.2.840.113549.1.7.1, aka
id-data from RFC 3369. Comments indicate that that the goal is to
intentionally prevent OpenSSL from recognizing the CMS id-data OID.
There are three big problems here:
1. There are obvious thread-safety issues. PKINIT does not protect its
counter and OpenSSL does not protect its mutable table.
2. The OBJ_cleanup call will throw away any mutable table entries
created by other callers of OpenSSL.
3. The shadow entry for id-data could interfere with other callers of
OpenSSL. In fact, the registration is explicitly deferred to avoid
breaking "things like the use of pkcs12" within PKINIT itself.
To solve these issues, we should avoid using the mutable table. The
work for this breaks down as follows:
* Six of the OIDs are only used to compare against OIDs from received
messages or certificates. These can be created as anonymous OIDs with
OBJ_txt2oid and freed with ASN1_OBJECT_free.
* The other four OIDs (including the shadowed one) are converted to NID
and passed to PKCS7_set0_type_other, which converts the NID back to an
ASN1_OBJECT pointer and sets the PKCS7 handle's "type" field to that.
Converting to NID and back won't work with an anonymous OID. Since the
PKCS7 structure is public, we could avoid using PKCS7_set0_type_other
and just do it ourselves, using a duplicate of an anonymous OID for the
type.
* We have to stop shadowing the CMS id-data OID. More analysis is
required here. Unfortunately, the need to prevent OpenSSL from
recognizing id-data relates to draft9 compatibility, which is not
covered by automated tests.
More information about the krb5-bugs
mailing list