Re: [Spasm] [saag] Best practices for applications using X.509 client certificates

Sean Leonard <dev+ietf@seantek.com> Mon, 26 September 2016 19:09 UTC

Return-Path: <dev+ietf@seantek.com>
X-Original-To: spasm@ietfa.amsl.com
Delivered-To: spasm@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id B6B9912B2A7; Mon, 26 Sep 2016 12:09:08 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -2.601
X-Spam-Level:
X-Spam-Status: No, score=-2.601 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_PASS=-0.001] autolearn=ham autolearn_force=no
Received: from mail.ietf.org ([4.31.198.44]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id M0NLQFzEs43s; Mon, 26 Sep 2016 12:09:02 -0700 (PDT)
Received: from mxout-08.mxes.net (mxout-08.mxes.net [216.86.168.183]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id B7C8A12B26E; Mon, 26 Sep 2016 12:09:01 -0700 (PDT)
Received: from [192.168.123.7] (unknown [75.83.2.34]) (using TLSv1.2 with cipher DHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) by smtp.mxes.net (Postfix) with ESMTPSA id 1DE3950A84; Mon, 26 Sep 2016 15:08:59 -0400 (EDT)
To: David Woodhouse <dwmw2@infradead.org>, spasm@ietf.org, Security Area Advisory Group <saag@ietf.org>
References: <1474280601.144982.263.camel@infradead.org> <CAPt1N1n_ff_QMYiRoorwvVnnP-Q6oruUE9_pvVr+QabeYJ+WrQ@mail.gmail.com> <CACsn0cnsswBX_-P+=Nd42uXAjPPXedXCefQ+V7R+aZn3U9XNog@mail.gmail.com> <CACsn0c=xHisLqPQzMHKr-0c_MEwM9_Nzq3tKmih5uZTYBnibGg@mail.gmail.com> <CACsn0ckABVfiJ506-uYRG+FXpGQixrS_9nxq6tPXfRu1kG_3pw@mail.gmail.com> <1474314996.144982.391.camel@infradead.org> <22611.1474382971@obiwan.sandelman.ca> <D2D83C89-12A2-4562-970A-92FAD232DD3B@deployingradius.com> <1474387598.144982.452.camel@infradead.org> <6A89750D-EAF8-45A0-97AD-0137A2CB8352@seantek.com> <1474881447.45169.205.camel@infradead.org>
From: Sean Leonard <dev+ietf@seantek.com>
Message-ID: <1eb84be4-1c5a-066e-f82d-1cd98c2dddd0@seantek.com>
Date: Mon, 26 Sep 2016 12:10:41 -0700
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.3.0
MIME-Version: 1.0
In-Reply-To: <1474881447.45169.205.camel@infradead.org>
Content-Type: text/plain; charset="utf-8"; format="flowed"
Content-Transfer-Encoding: quoted-printable
Archived-At: <https://mailarchive.ietf.org/arch/msg/spasm/F8-M-qOxvuqNN3eGhc4fSYnfwB8>
Cc: Michael Richardson <mcr+ietf@sandelman.ca>, Alan DeKok <aland@deployingradius.com>
Subject: Re: [Spasm] [saag] Best practices for applications using X.509 client certificates
X-BeenThere: spasm@ietf.org
X-Mailman-Version: 2.1.17
Precedence: list
List-Id: "This is a venue for discussion of doing Some Pkix And SMime \(spasm\) work." <spasm.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/spasm>, <mailto:spasm-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/spasm/>
List-Post: <mailto:spasm@ietf.org>
List-Help: <mailto:spasm-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/spasm>, <mailto:spasm-request@ietf.org?subject=subscribe>
X-List-Received-Date: Mon, 26 Sep 2016 19:09:09 -0000

On 9/26/2016 2:17 AM, David Woodhouse wrote:
> On Sun, 2016-09-25 at 18:48 -0700, Sean Leonard wrote:
>> Hello David:
>>
>> draft-seantek-certspec “Textual Specification for Certificates” is
>> exactly what you’re looking for.
>>
>> https://tools.ietf.org/html/draft-seantek-certspec-09
> Thanks; that's very interesting. I'm not sure it covers exactly the
> same use case, but it's very closely related.

Great!

>
>> That is for certificates. And yes, it handles pkcs11 just like
>> everything else.
> ... but not like RFC7512 does, I note. Is it worth trying to achieve
> some better consistency there? After all, I can *already* refer to the
> certificate in my crypto token consistently as
>
> 	'pkcs11:manufacturer=piv_II;id=%01'
>
> in a variety of applications using different crypto libraries. And in
> fact on my operating system of choice I can file a bug for any
> application which *doesn't* accept that string, when it would have
> taken a filename. So I'd definitely like to see your draft make
> explicit reference to RFC7512 in some form or other.

I can do that...although the value of doing so may be a bit lost on me. 
The general syntax would be:

URI:pkcs11:manufacturer=piv_II;id=%01

The syntax of "URI:uri" (with URI: prepended) has a long and tumultuous 
history. You can look at the draft history to see why.

Applications for draft-seantek-certspec are hunting for certificates on 
the order of sub-milliseconds: looking up a certificate could be done in 
a blocking operation. This would be the case, for example, when a TLS 
server (web server, IMAP server, etc.) or client boots up and needs the 
certificate before starting its first TLS connection. As a general 
matter, URIs strongly imply network access; therefore they are not as 
important as the other types of specs.

Any application that plans on using a certificate with its corresponding 
private key should obviously have the certificate on-hand and 
at-the-ready. Even if the private key is unavailable (e.g., the hardware 
token is not in the slot), some pointer that shows that a private key is 
known to be around, has to be immediately available. That way the UI can 
prompt the user for the right device.

A distinguishing feature of URIs is that it is limited in its repertoire 
of characters to a strict subset of ASCII, with % percent-encoding. This 
means that LDAP strings are going to look very convoluted, with a lot of 
%20, %2F, %3B, etc. throughout. If you want to permit users to specify 
strings without double or triple % encoding and \ escaping and whatnot, 
then I can buy an argument to promote "p11:" or similar to the top of a 
certspec, and not buried into the "URI:" spec type. There is precedent 
for this because there are already BASE64 and HEX specs, which duplicate 
URI:data: in functionality, but are demonstrably easier to use.

By the way, RFC 7512 contains a serious bug: the | character is not 
valid in URI [RFC3986]. I don't know how that character snuck through 
the RFC process, but it's not a valid URI.

RFC 7512 contains a second, less serious bug: "The URI scheme does not 
use the fragment component." Well that may or may not be good advice. I 
don't see why a PKCS #11 token can't return a blob that is plain text 
(text/plain), in which case, fragment would be defined by RFC 5147. 
Furthermore, PKCS #11 is actually Internet media type-aware: see 
CKA_MIME_TYPES, for example, in that standard.

>
>> ***
>>
>> Private keys are another matter. The approach could easily be
>> extended to handle private keys. They are just identifiers, after
>> all. However, by definition secure private keys are a “local matter”.
>> I do not see the value of standardizing an identifier for private
>> keying materials when the implementations are all different and are
>> not supposed to communicate with each other.
> Ah, but that is *precisely* the matter I was most concerned about. It's
> not so much about implementations communicating with each other; it's
> about consistency and (hence) usability.
>
> Not very long ago, in order to use that key in the crypto token I
> mentioned above, I had to do something *different* for fairly much
> every application:
>
>   • for OpenVPN, I had to manually specifier the PKCS#11 provider
>     module and use one form of identifier string.
>   • for OpenConnect, RFC7512 identifiers Just Worked, and it used
>     the PKCS#11 providers indicated by the system configuration. (Yay!)
>   • for Curl (if built with NSS) I needed to manually edit configuration
>     files to make it load the right module, and then refer to the
>     object by a *third* form of identifier string.
>   • for wpa_supplicant I had to manually configure it to use an OpenSSL
>     "Engine", specify the provider in yet *another* different manner
>     because that also ignored the system configuration, and then give
>     the certificate ID in a *fourth* different form.
>
> And that was just for the applications which *could* use PKCS#11. Many
> just couldn't do it at all. And for some, they needed to be configured
> differently depending on which crypto library they'd been built
> against.
>
> It made me kind of sad. FWIW I have all of the above just taking
> PKCS#11 URIs according to RFC7512 now, without any of the additional
> configuration nonsense like loading engines and specifying provider
> modules.

That is indeed a list of horribles.

But for applications that are PKCS #11 based, one could easily write a 
script that takes a pkcs11: URI as input and outputs the right flips, 
switches, config files, and API calls to do what the pkcs11: URI is 
saying to do. Probably would take less than a day.

For applications that are *not* PKCS #11 based (macOS Keychain Services, 
Windows CNG), using a PKCS #11 URI would be..."grotesque". I don't know 
of a better way to put it.

>
> Now, *part* of that is addressed by your draft (although it's already
> addressed by RFC7512 in the case of PKCS#11, and the conflicts there
> want resolving). But other parts are not — and I'm not sure you really
> want to expand your scope to cover them. They include:
>
>   • Using the system configuration for which PKCS#11 providers to load.
>   • The search algorithm, identifying when to log in to a token to
>     attempt to find a certificate with CKA_PRIVATE and how to locate
>     the key corresponding to a given certificate, etc.
>   • The requirement that opaque private keys without access to the
>     corresponding public key SHALL work.
>
> That's just for PKCS#11. of course. For files there are a different set
> of issues — mostly the fact that every application on the system will
> currently support a *different* subset of private key file formats. So
> a user with a certificate+key provisioned through her organisation's
> proprietary scripting will find that it works with *some* applications
> and not others, for reasons which are entirely intractable, such as:
>
>   • It uses the non-standard OpenSSL 'encrypted PEM' format.
>   • It uses a SHA256 HMAC which isn't universally supported.
>   • It is encrypted with DES-MD5, which isn't universally supported.
>   • It is in DER form, which applications need to jump through hoops
>     to cope with loading because crypto libraries hate us all.
>
> The idea of my draft is to give a set of "best practice" guidelines for
> applications so that the user *can* just use the same certificate and
> key with any well-behaved application, with exactly the same
> identifier, and it will Just Work.
>
> It's not *just* about the identifier though, and in fact I've mostly
> tried to make it *not* about the identifier. I just defer to RFC7512
> and obviously to filenames. For the system certificate stores I just
> say that if a convention exists, it should be supported — and it sounds
> like your draft would be the ideal solution to fill that gap.
>
> So while there is certainly an overlap with your draft, there's also a
> lot to cope with that *isn't* already the primary target of your draft.

Okay. Yes, the primary target of the draft is identifying certificates 
(uniquely and unambiguously), and providing associated attributes with 
the certspec. Interestingly, one of those "associated attributes" could 
very well be: "hint or directive about where to find the private key". 
So that is a point of extension that we could collaborate on, whether in 
draft-seantek-certspec or in a related draft.

For interoperable private key formats, I favor PKCS #8 PrivateKeyInfo 
(as .p8) and PKCS #8 EncryptedPrivateKeyInfo (as .p8e). They are 
standardized, widely-supported, and algorithm-agile. They are also 
simple enough that even if a crypto stack doesn't support them directly, 
"adapters" can be built that shoehorn the data into other container 
formats, such as PKCS #12, OpenSSL's proprietary formats, and so on. 
(Note that I worked on the registrations for both application/pkcs12 and 
application/pkcs8-encrypted.)

> If you want, I'm happy to work with you to *make* your draft cover
> this. But I suspect there would be sufficient conflict in our use cases
> that it's best just to ensure that they complement each other to
> achieve their respective goals. What do you think?

I am happy to make draft-seantek-certspec more useful to different 
constituents!

The focus needs to remain on uniquely identifying cryptographic data 
items, rather than as a generalized querying format. (Discussed in 
draft.) However, I like the idea of a standardized attribute that points 
to the location of a private key. Such an attribute could also be 
conveniently serialized into other formats, e.g., as attributes in PKCS 
#11 and PKCS #12, and as Certificate Properties in Microsoft CryptoAPI. 
That is exactly how crypto stacks operate anyway: they tag a certificate 
with a little pointer that points to where to find the private key, if 
one exists.

>
> For reference, the current version of my nascent draft is at
> http://david.woodhou.se/draft-woodhouse-cert-best-practice.html and
> it's also at https://github.com/dwmw2/ietf-cert-best-practice

Thanks, I read it.

>
>> You can, of course, always refer to a private key indirectly, by
>> referencing an associated certificate. It is very plausible to
>> identify a certificate stored in a local file (that does not need to
>> be encrypted), and then to look up the associated private key on a
>> token that has a lot more protection around the key, by using the
>> certificate or its metadata as the dbkey/index.
> Yes, there is lots of fun to be had here. Lots of reasonable heuristics
> for how to find a key given the certificates — and thus lots of scope
> for applications to be inconsistent and for users to complain "it works
> in XXX, so why doesn't exactly the same cert work in YYY?".
>
> I've attempted to address this with the search algorithm for PKCS#11.
> For files there's not a lot you can do although I do mention that if
> the cert has extension '.crt' and doesn't actually contain the private
> key, you might look for a corresponding file with extension 'key'.
>
> There are probably more improvements that can be made in this area,
> especially when it comes to the system stores on Windows and OSX.

Okay.

>> [The aforementioned paragraph is also responsive to Ted Lemon’s
>> concern: “one concern I have about it is that we actually really
>> don't want applications to have access to private keys.”]
> Yes, we absolutely need to support and encourage that use case. That is
> part of my motivation for pushing to have PKCS#11 supported
> consistently across applications on platforms where that's the best
> answer.

Good.

Regards,

Sean