Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature - Attestation #45

Open
mistial-dev opened this issue Apr 14, 2022 · 4 comments
Open

Feature - Attestation #45

mistial-dev opened this issue Apr 14, 2022 · 4 comments

Comments

@mistial-dev
Copy link

Looking at things from a CMS standpoint, attestation certificates in some form or another help provide assurance that keys were generated on-module. As an example of such a process from the windows server documentation:

Every TPM ships with a unique asymmetric key, called the Endorsement Key (EK), burned by the manufacturer. > We refer to the public portion of this key as EKPub and the associated private key as EKPriv.
Some TPM chips also have an EK certificate that is issued by the manufacturer for the EKPub. We refer to this cert as EKCert.
A CA establishes trust in the TPM either via EKPub or EKCert.
A user proves to the CA that the RSA key for which the certificate is being requested is cryptographically related to the EKPub and that the user owns the EKpriv.
The CA issues a certificate with a special issuance policy OID to denote that the key is now attested to be protected by a TPM.

YubiKey PIV support does something similar by burning in a key and certificate that is used to essentially issue X509 certs for public keys on the YubiKey, with metadata about the slot (PIN and Touch policy) present. This allows card management software to identify the serial number of the token, verify that it was generated within the cryptographic boundary, ensure the appropriate PIN policy is set, and that it is in the appropriate DO (which matters in terms of Windows assumptions with the built-in PIV driver).

There are three specific use cases in which attestation is extremely useful for card issuers.

The first is for organizations that wish to buy or make a batch of cards. These cards would be initialized with an attestation key (exactly like YubiKeys are now), and could be provided to users later for remote personalization. This can greatly aid in legal non-repudiation, as the keys are generated and the certificate issued only after the user has taken physical possession of the card and set the PIN.

The second use is for easy re-keying. Given the industry trends towards shorter certificate and key lifetimes (something the CA/Browser forum enforces for web browsers), users will need to re-key and re-issue certificates more often. Doing so without attestation, however, increases the chance of a user providing a CSR for keys not protected within a hardware cryptographic boundary.

The third use is to assist with compliance requirements. For example, Adobe Trust List (PDF signing) requires:

All end-entity key pairs must:
(a) be generated:

  1. either by using a trustworthy system, taking all reasonable precautions to prevent any
    loss, disclosure, or unauthorized use of the private key, and then securely transferred
    in a secure cryptographic hardware device conform to (c) below, or,
  2. directly generated by and stored in such a secure cryptographic hardware device

SSL.com uses YubiKey attestation to allow them to meet these requirements on user-possessed tokens, keyed and re-keyed in the field.

Would some sort of attestation mechanism make sense for OpenFIPS201?

@makinako
Copy link
Owner

Hi @mistial-dev, yes this has been on the non-allocated TODO list for a while now. The idea of identifying whether a key has been generated or imported makes total sense, it's just how to effectively do it.

Yubikey has it's F9 key, which as you described is comes factory-populated by their own key with an established trust chain. The same is true for the TPM EK's as you've described.

OpenFIPS201 doesn't have that luxury being a self-installed applet, so the remaining options are:

  1. Have individual generated keys self-sign
    Since the key will most likely be permitted to sign arbitrary host-supplied values after generation, this is out.

  2. Generate the attestation key pair off-card and inject it
    The entity that generated the attestation certificate in the first place can sign attestation certs now, so this seems out.

  3. Generate a unique per-card attestation key at applet install or similar
    This seems to be the remaining option, but there needs to be a chain of trust in place here.

What would you think of something like the following?

  1. Add an Options.attestationKey configuration param or something similar to indicate which key is used for attestation (0 for disabled)
  2. During pre-perso, you must also define this key and OF201. It would have to have a (newly created) ROLE_ATTEST flag set and would need to be prohibited from having any other role, or the 'importable' attribute set.
  3. The CMS generates that key, pulls the public value, signs it and possibly decorates the cert with an Attestation OID and writes it to whichever data object it decides is the attestation cert.
  4. During key generation, OF201 will check if Options.attestationKey is non-zero and if so (and the attestation key is populated), it will generate the attestation cert for the generated key. I guess it does this for itself too?
  5. When key enumeration is completed (should be next minor release), return a flag to show if each key is imported or generated.
  6. The user calls a Get Attestation command on a given key id/mechanism pair. If attestation cert is available this is returned.
  7. When General Authenticate is called, the key associated with Options.attestationKey could not be used for any purpose. This would be implicit in the enforced roles/attributes, but we might add a double-check here anyway because it's cheap.

This is very rough, but doesn't seem too significant to implement and so could be considered.

@mistial-dev
Copy link
Author

OpenFIPS201 doesn't have that luxury being a self-installed applet,

That's going to depend on the organization making the cards. As an example, I know of one org that is looking to have a card manufacturer load a bunch of PIV cards with applets for them. The card mfg could easily provision some key to all the cards.

Generate the attestation key pair off-card and inject it
The entity that generated the attestation certificate in the first place can sign attestation certs now, so this seems out.

Not necessarily. If a company wants to know "this is one of our cards", then injecting it themselves makes perfect sense. They know it's one of their cards, even if the user (or issuing department) generates new keys.

Ultimately, the organization that issues the attestation certificate does have the capability to either inject it to multiple devices, or to generate certificates for keys not generated on some cryptographic module. For a government, or a company (the general users of this), a key they control is still extremely useful, even if that attestation becomes meaningless to third parties.

If a manufacturer chooses to use this to make OpenFIPS201 cards available, then the cards themselves are only as trustworthy as the manufacturer. The manufacturer could backdoor the applet anyway, which gets you essentially to where things are with YubiKeys. They take reasonable care, and if you rely upon that signature, you are ultimately trusting them.

The same is true with most cryptographic modules, come to think of it. The rather expensive HSMs I use for work still ultimately rely on me trusting the manufacturer to not backdoor them, and to not issue bad firmware for them. Even with an Open Source HSM, I'm trusting that's the applet that's loaded if I didn't compile and load it myself.

Generate a unique per-card attestation key at applet install or similar
This seems to be the remaining option, but there needs to be a chain of trust in place here.

That's one of the things we're looking at doing. The practical reality is that it slows down the card issuance process tremendously, but it increases security if the module itself is compromised. With YubiKeys, their loading of one attestation key to multiple devices means that a compromised device potentially can be used to fake other devices. That's less of a risk with per-device attestation keys, but that also potentially provides a mechanism to identify the user (which is why FIDO2 requires the same attestation cert to be used on 100,000+ devices).

@mistial-dev
Copy link
Author

As for your workflow:

Add an Options.attestationKey configuration param or something similar to indicate which key is used for attestation (0 for disabled)

Making it disableable makes sense.

During pre-perso, you must also define this key and OF201. It would have to have a (newly created) ROLE_ATTEST flag set and would need to be prohibited from having any other role, or the 'importable' attribute set.

What do you mean by "and OF201"?

Having attestation be a defined role is a good thing, as there are quite a few attacks that rely on using keys for the wrong things. I don't think that importation itself is a bad thing, especially when used properly. For example, in my CMS now, I'm using a PKCS11 HSM to generate per-device certificates and keys (in the interest of time). They aren't retained, they are unique, and it's much, much, much faster than trying to generate a keypair on card and have it do a signature operation.

The CMS generates that key, pulls the public value, signs it and possibly decorates the cert with an Attestation OID and writes it to whichever data object it decides is the attestation cert.

The attestation OID serves a couple purposes. One of the important ones is that the card is essentially a CA, so it's a good place to put a nice critical extension to poison pill it for anything other than attestation. If an application doesn't know what an attestation cert is, it shouldn't accept it.

PIVApplet writes its own self-issued CA certificate, which means that if you do an attestation at initialization you can store the public key of the CA, and use it to verify future attestation certs generated by the card.

It doesn't set subjectKeyIdentifier or authorityKeyIdentifier, which is a problem for a CMS (as building the path is difficult), but that's one of the things being changed in my upcoming patch. When the CA is just "PIVApplet Attestation Cert", for every card, with different keys, it's a pain.

With the subject and authority identifiers, it's relatively straightforward for a CMS to just let the cards issue their own certs, store them, and validate any later cert based on the authority key identifier.

In the interest of speed and space, I've made the generation of this key and cert optional. PivApplet just generated it automatically without returning the public key, which made it difficult to use.

My upcoming pull request changes this to empty attestation by default (since it's fairly useless on its own). A CMS can call generate on the F9 slot, and get the public key returned to it. This will be the authority key identifier on any subsequent attestation cert. I'm also placing the card UUID into the issuer CN, to further help in identifying cards and their certificates.

During key generation, OF201 will check if Options.attestationKey is non-zero and if so (and the attestation key is populated), it will generate the attestation cert for the generated key. I guess it does this for itself too?

Why not generate the certificate on demand? PivApplet (and yubikeys) just keep track of whether or not a key is generated on card, and refuse to issue attestation certs on imported keys.

This way, normal operation of the token is unaffected.

As for doing it for itself, a self-signed one works if one is looking to use this only within a CMS. There are situations (like Adobe Trust List) where it's better to have this attached to a root of some sort. As such, it is nice to be able to import a signed attestation CA (what goes in the F9 slot on a yubikey).

With YubiKeys, that CA can be a root or an intermediate. The certificate is parsed to get the subject, which gets written into the issuer field on the attestation certificates themselves. They are x509, verifiable with OpenSSL, issued to the public key of the generated key, signed by the F9 key.

When key enumeration is completed (should be next minor release), return a flag to show if each key is imported or generated.

Useful. Attestation makes this more secure, but if done over a secure channel it could be done remotely in a reasonably secure and trustworthy manner.

The user calls a Get Attestation command on a given key id/mechanism pair. If attestation cert is available this is returned.

From a memory/space tradeoff, why not calculate that signature then?

When General Authenticate is called, the key associated with Options.attestationKey could not be used for any purpose. This would be implicit in the enforced roles/attributes, but we might add a double-check here anyway because it's cheap.

Absolutely makes sense.

@makinako
Copy link
Owner

Hi @mistial-dev, just wanted to let you know I've been on leave but still have this on my list to reply to.
Once I'm back on board (~9th May) so I'll try to address any questions then, and meanwhile we will discuss adding this internally, get more specific on the design and feed it back to this comment chain before going ahead, but your feedback and suggestions have been really useful, so thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants