Subject: [Openpgp-dt] v5 keys and hardware tokens (issue #63)

From: Daniel Kahn Gillmor <[email-masked]>
Date: Thu, 10 Mar 2022 01:59:33 -0500

An outstanding concern we have is our story about using hardware tokens
with OpenPGP:

   https://gitlab.com/openpgp-wg/rfc4880bis/-/issues/63

In particular, the OpenPGP smartcard specification explicitly identifies
OpenPGP keys by 20-octet fingerprints:

   https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.1.pdf

I'm not a smartcard expert, but here's what i think i understand (i hope
the more expert folks in this group can correct me):

An OpenPGP smartcard can store three secret keys: one for signing (SIG),
one for decryption (DEC), and one for authentication (AUT).

The public keys data for each of these three secret keys can typically
be extracted from the card, but they will be the raw public key
material, not stored in full OpenPGP format.  Some cards may not be able
to produce the full raw public key material available, or may have it
wrong, somehow. Or maybe it's expensive to retrieve?  (when/why is it
not available?)

Alongside these keys, the card stores metadata fields that correspond to
the keys.  for each of these three keys, there is at least these
non-optional fields:

 - 4 octet creation date (unix timestamp)
 
 - 20 octet fingerprint identifier

 - a "cardholder certificate", an arbitrary blob (expected to be X.509)
   that is out of scope of the OpenPGP spec

all of these slots are arbitrarily writable, and the card does not
enforce that they adhere to any particular fingerprinting scheme.

The card as a whole is also required to accept the following general
fields (not associated with any particular key):

 - 0-39 octets of "Name", formatted in a particular flavor of ASCII

 - 1 octet of "Sex"

 - arbitrary-length field of binary, proprietary "login data"
 
 - arbitrary-length field of "URL", which is intended to point to a place to download the full certificates

 - 2-8 octets of language preferences.

In addition to these data points, the card also has three additional
read/write 20-octet "fingerprint" slots for fingerprints of trusted CAs.

As v5 fingerprints are 32 octets, not 20 octets, they don't fit nicely on these
cards.

As i understand it, the biggest concern we have is that some
applications rely on the fingerprint field from the card in order to
retrieve the OpenPGP fingerprint from the network.  Presumably this is
donen because extracting the public key material from the card to create
an OpenPGP public key and thereby derive the fingerprint is not always
possible.

I see several possible ways we can go forward with v5 keys on
existing smartcards:

 a) assert that existing smartcards are for v4 keys only, and require an
    update to the card (or buying a new card) to make it work with v5
    keys.

 b) assert that the secret key material can be stored in these cards and
    used with them, but v5 fingerprints will not be stored.  fingerprint
    fields for v5 keys will be set to a fixed magic value (maybe 20
    octets of 0x05 ?).  The cards can only be used if the user can
    extract the public key material from the card, formulate a v5 pubkey
    from it, and compute the fingerprint directly via local computation,
    not on the card.

 c) truncate v5 fingerprints to 20 octets and stuff them in the
    truncated slots.  The implementation using the card has to guess
    whether the corresponding public key is v5 or v4.

 d) some sort of compromise, like putting a magic value in the first 12
    octets of the fingerprint, and storing only the v5 key ID (8 octets)
    in the fingerprint field.  A reliant implementation checks for the
    magic value in the upper 12 octets, and has to work from the key ID,
    not the fingerprint, if it is unable to compute the fingerprint from
    the extracted pubkey material.

 e) cannibalize some other data field(s).  For example, cannibalize the CA
    fingerprint: when storing a v5 key in the SIG slot, store an 8-octet
    magic value concatenated with the low 12 octets of SIG key
    fingerprint, *and* overwrite the first CA fingerprint slot with the
    high 20 octets of the SIG key fingerprint.  same step applies for
    the DEC fingerprint and the second CA fingerprint, and AUT and the
    third CA.  A v5-aware application will check the fingerprint slot
    for the magic value, and if it finds it, extracts the rest of the
    fingerprint from the cannibalized fingerprint slot.

    If the CA fingerprint slots are too important to lose for the sake
    of storing a v5 key (are they?  who uses them and how?)  It's not
    too hard to imagine cannibalizing part of the URL field for this
    purpose instead of cannibalizing the CA fingerprint slots.  For
    example, store the remaining parts of the three fingerprints as
    base64-encoded blobs in a "#fragment" at the end of the URL.  But
    the max length of the URL field varies from card to card (see page
    33 of the spec) and it's not clear that there will always be enough
    room. We'd need 96 base64-encoded characters in the fragment to
    represent three sets of 20-octets, plus 1 octet for the fragment
    delimiter character "#".  That's 97 chars (3*32 + 1) in the URL
    field. (what are the most common lengths permitted for the URL in
    popular cards?)

    Alternately, if space is really tight, we could signal that the key
    is a v5 key by using fewer octets, for example by cannibalizing part
    of the first octet of the key creation date field: if the first four
    bits that field are all zero (an implausibly early timestamp, no
    later than 1978-07-04), then the key is a v5 key; reconstruct the
    timestamp by left-shifting the field by 4 bits (key generation must
    clear the low four bits of the creation timestamp). The fingerprint
    field stores 20 octets of the fingerprint, and we just need to find
    another 12 octets for the rest of the fingerprint.  Using a
    b64-encoded fragment in the URL field to store the remaining three
    fractions consumes only 59 chars (ceil(12*3*8/5)+1).  But that's
    starting to get pretty complicated.

Does anyone have a preference for any of these choices?  or a strong
objection to any of them?

          --dkg

---

From: NIIBE Yutaka <[email-masked]>
Date: Wed, 16 Mar 2022 21:18:14 +0900

Hello,

Daniel Kahn Gillmor wrote:
> material, not stored in full OpenPGP format.

Right.  Only raw public key material is available, it's not in OpenPGP
format.

> Some cards may not be able to produce the full raw public key material
> available, or may have it wrong, somehow. Or maybe it's expensive to
> retrieve?  (when/why is it not available?)

For all OpenPGP card implementations (I know of), after user generates
or loads key on smartcard, public raw key material is always avaiable.
I don't know any implementation which can not retrieve raw key material.

>  - arbitrary-length field of "URL", which is intended to point to a place to download the full certificates

For GnuPG, a user can do:

    gpg --card-edit -> fetch

to retrieve OpenPGP key from the URL.  (It was useful before WKD.)
It's because there is no (defined) space on card to store OpenPGP key.

> As v5 fingerprints are 32 octets, not 20 octets, they don't fit nicely
> on these cards.

Yes.

> an OpenPGP public key and thereby derive the fingerprint is not always

If we can assume some constants (like ECDH KDF parameters), OpenPGP
fingerprint can be derived with raw public key material plus timestamp.
When I tested in the past (in 2019) for v5 key, I did that.
--