curl / Mailing Lists / curl-library / Single Mail


Re: Multi-threading, NSS, client certificates and Linux problem

From: Pawel Veselov <>
Date: Fri, 20 Jan 2017 16:41:35 -0800

On Fri, Jan 20, 2017 at 3:35 AM, Kamil Dudka <> wrote:
> On Thursday, January 19, 2017 13:39:44 Pawel Veselov wrote:
>> Things work perfectly fine if I use the database, i.e. no MT problems.
>> Unfortunately, this is not a workaround to what I'm trying to achieve,
>> but it is pointing to nss-pem as a culprit, isn't it?
> Exactly.

I tried using PKCS#12 format for authenticating, but I can't make it work
either. I set the certificate type to P12, but simply get "NSS error -8018
(SEC_ERROR_UNKNOWN_PKCS11_ERROR)". Curl application simply rejects P12
certificate type, so don't know what's up with that.

>> Anywhere in particular you'd like me to dig in there?
> The nss-pem module maintains a global array of objects named pem_objs. I
> guess it could be a problem if accesses to the array were not synchronized.
> But they should be thanks to the patch I referenced in my previous reply.

Well, I'm not familiar with curl or nss code so it's not easy for me to
understand this.

I'm looking at the code in nss_create_object, and is already a bit confused.
On the face of it it looks like the method creates some sort of "slots" with
NSS library, and there are ever only two potential names for these slots -
"PEM Token #0" or "PEM Token #1", depending on whether the certificate being
loaded is CA or not.

The function uses this slot during its execution, only locking it out when
the slot is being "found" (in nss_find_slot_by_name). I see that
PK11_CreateGenericObject() function uses a full lock when working with the
slot (EnterSlotMonitor/ExitSlotMonitor). The private key is loaded separately.
I haven't figured out all the logic, but the following sequence
strikes me as odd, I don't understand how things would work in this

Consider nss_load_key (it doesn't matter what's going here, I just see that
the slot object is freely used by multiple threads that seem to store some
information into it, which can be easily overwritten by other threads).

thread#1 calls nss_create_object on key#1
thread#2 calls nss_create_object on key#2
thread#1 calls PK11_Authenticate (password)

At that last point, the only input is slot ID and password, I don't
see how it can possible know to operate on key#1, and not key#2...

If you could please help me understand how the MT is realized on these
slots, and where does it happen that certificate/keys are actually
written out to the TCP socket, it would be very helpful. The
documentation for PK11 is scarce to
come about (if you have a pointer to that, it'd be very helpful as well :) )

> Are your private keys encrypted?

They are not encrypted.

>> P.S. I also discovered that if database is used (even if it just
>> exists, may be it needs to have a CA, may be it doesn't), then
>> CURLOPT_CAINFO is ignored, or at least the cert that is provided by it
>> is no longer trusted. May be because the same cert is in the DB, and
>> without the C flag. If it is the latter, it is probably still a
>> problem, because if I say I need to trust cert X, there is no other
>> way for me to do it (if it is a system database, for example).
> You can try it with your own (e.g. empty) NSS database. You can set the
> $SSL_DIR environment variable to make libcurl use a different database.

It's a stretch, sure, but the problem is:
* server's cert is signed with caXX
* client's cert is signed with caXX (same CA)
* you import client's chain into the cert database (CA gets imported, but
  left in there without trust)
* You don't want to enable trust for this CA for all connections
* You only want to enable trusting the CA explicitly when you need to.
* NSS always picks caXX from the database, even if it is specified as
  "trusted" separately, and because it's not marked as trusted in the DB,
  doesn't accept server's certificate.


I also noticed this other thing in the code, may be I'm wrong.
The documentation says that to avoid conflicts between using file names and
certificate aliases for NSS, the use should prepend './' to the relative
file names. However, the code (nss_load_cert) checks if the file exists
first. So if there is a file at CWD/nick, it's not possible to use the
nickname, no?
Received on 2017-01-21