-
Notifications
You must be signed in to change notification settings - Fork 6
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
Add TPMKMS support #71
Conversation
In the `crypto/kms` package, the `CreateAttestation` implementation for YubiKeys was changed to include the leaf as the first certificate in the chain. Looping through the chain is thus sufficient for getting all certs including the leaf in PEM format.
A KMS URI can now be provided using just the scheme, without a colon. E.g. `--kms tpmkms` is now a valid value. Before this change, providing `--kms tpmkms` would result in an error: `Error: error parsing tpmkms: scheme is missing`. It isn't immediately clear that it's the colon that's missing, so decided to make the KMS URI processing a bit smarter.
Added a flag `--bundle` to `step kms certificate`. For the case in which a certificate is only printed, a `CertFS` implementation is used, which doesn't currently support reading chains. Added a workaround to read from a `CertificateChainManager` instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, but I would bundle by default, it is what we were doing before.
@@ -116,4 +175,5 @@ func init() { | |||
flags.SortFlags = false | |||
|
|||
flags.String("import", "", "The certificate `file` to import") | |||
flags.Bool("bundle", false, "Print all certificates in the chain/bundle") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would print the bundled certificate by default. A different option can be added to show only the leaf. Probably something cleaner that --bundled=false
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've left this as is, to be consistent with our other tooling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
step-kms-plugin certificate
is mainly used to load a certificate from a KMS when step ca certificate --x5c-cert
is used. The --x5c-cert
flag expects a bundled certificate, that is what you will use with files. The flag --x5c-chain
was added to support a bundled certificate in those KMSs that only support a single certificate. There is some inconsistency because not all KMSs support the same things, but I don't think we want to add --x5c-chain
unless it is necessary.
We can keep the flag here, for "consistency" with step certificate inspect
, but we will need to change the cli to add the --bundle
option. This will cause some incompatibility depending if you are using the last version of the plugin or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #71 (comment).
Is it, though? There was only (Load|Store)Certificate, which would work with / return a single certificate? I may have missed something, but that was the reason to add the CertificateChainManager. So now, when the KMS supports chains, the default is to show just one cert in the output. |
The other KMSs only support one, but for example in attest we show the bundle. |
Now I get what you mean! Yes, the behavior changed slightly for the YubiKey, due to adding the leaf as the first cert of the chain, and not looping through the entire chain now. I think for For attestation use cases, I think most users will need the chain by default, so I agree that we may want the behavior of |
Not entirely sure if this is the correct place for this "informational note": For TPM wrapped keys, there is a file format defined at https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html (PEM files containing The vision is that any software which can use keys from a file, should automatically recognise when the file they're given contains such a key (in either PEM or DER form) and Do The Right Thing™. Tools which create keys to be used with a TPM should also use this storage format or at least be able to export to it. |
@dwmw2 thank you for your insight! 🙂 I was just looking through your comment on smallstep/crypto#260, and saw the the link to your draft RFC, which in turn linked to the TPMKEY URI draft. That draft did inspire parts of our TPMKMS implementation, as well as the underlying packages. We chose to start with We're close to making We currently default to storing the serialized TPM objects (and corresponding certificates) as files in a directory. The files themselves contain a JSON representation of the TPM objects, which includes the serialized TPM data, as well as some metadata. It's a simple and effective solution and we don't need to maintain an additional (meta)data store that way. For the PEM format |
Note that the URI and the file format are fairly separate. The URI would be used for keys which are stored within the TPM, in its NV storage. There was that old tpmuri draft from @nmav for TPMv1.2, and I've recently been prodding the folks working on OpenSSL engines to get their act together and have a single form of identifier for TPMv2.0 too. The file format is for keys which are stored on the file system (or anywhere else really) in encrypted form and transiently loaded into the TPM as required. The standardisation of that one is much further along; @jejb's document is new but the format is already supported in released versions of both OpenSSL engines as well as OpenConnect and GnuTLS. Note that the file format does have implications about precisely how you generate the temporary parent key that wraps the stored key. Being able to export to this PEM form seems like a reasonable choice. I believe tpm2_tools can use it too, so you could perhaps do it instead of the older separate pubkey/privkey blobs that tpm2_tools supported? Again, we do have to ensure the generated parent is compatible. I think PEM headers should probably work, and you can also put stuff outside the |
Noted and understood!
That makes sense. Is it only for keys within the TPM, though? Because the old URI does support
That looks great! I don't remember having seen that document before, but it does describe things I've been thinking about to store in our own serialization format, such as auth policies. The underlying Go libraries we depend on don't support passing these through currently, afaik, but work's being done that might make that possible. So this definitely looks interesting to support in the (near) future.
👍
The
Headers feel a bit neater to me, but that additional data part at the end might be a nice alternative. We do have some utilities for PEM deser thay may, or may not support the latter, but we can probably add support for that. The Go stdlib seems to do the right thing already. One thing that our current format does, is storing any certificate (chains) belonging to an AK or key in the same file as as the serialized key data; with this PEM format, we may want to have a way to separate those into two files depending on how systems using the file want them to look like. |
I object vehemently to asking the user to tell the application what kind of thing is stored in the file. The application should just look in the file and Do The Right Thing. I hate the fact that OpenSSL has different APIs for opening different types of PKCS#(1|8|12) files, even for PEM vs. DER versions of the same format, which leads to tools like So asking the user to specify Note that the documentation of the TPMv2 format explicitly notes that it starts with an unambiguous OID specifically so that it can be detected even in DER form. OpenConnect will Just Work™ with whatever file it's given, whether it be a software key in one of the myriad of formats, a TPMv1 TCPA key blob, a TPMv2 file. Or if it isn't a file, and is instead a PKCS#11 URI of the form |
To make it possible to use the `attest` command similar to how it's used with a YubiKey, for TPMs we need to create a new attested key at the time of creating an attestation. This is because the data that is being attested when attesting the key is part of the input for the TPM when creating the key. It's still possible to do a normal `attest` flow. That requires creating an AK and key (with optional `qualifying-data` set) to be created first. Using the `--new` flag, a new key with `name` is created. This option is not yet documented in an example.
@maraino I added support for creating a new key when running The previous method, with the AK and key being created in separate steps, also still works. I'm trying to fix RSA >2048 bits keys now, which is why I put the default to that. Apparently I've been testing with 2048 all the time; this was used all over the place in Might need to upgrade my |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still unconvinced about the --bundle. I've added my reasoning in a comment.
@@ -116,4 +175,5 @@ func init() { | |||
flags.SortFlags = false | |||
|
|||
flags.String("import", "", "The certificate `file` to import") | |||
flags.Bool("bundle", false, "Print all certificates in the chain/bundle") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
step-kms-plugin certificate
is mainly used to load a certificate from a KMS when step ca certificate --x5c-cert
is used. The --x5c-cert
flag expects a bundled certificate, that is what you will use with files. The flag --x5c-chain
was added to support a bundled certificate in those KMSs that only support a single certificate. There is some inconsistency because not all KMSs support the same things, but I don't think we want to add --x5c-chain
unless it is necessary.
We can keep the flag here, for "consistency" with step certificate inspect
, but we will need to change the cli to add the --bundle
option. This will cause some incompatibility depending if you are using the last version of the plugin or not.
cmd/attest.go
Outdated
flags.Bool("new", false, "(EXPERIMENTAL) Creates and attests a new key instead of attesting an existing one") | ||
flags.Var(kty, "kty", "The key `type` to build the certificate upon.\nOptions are EC and RSA") | ||
flags.Var(crv, "crv", "The elliptic `curve` to use for EC and OKP key types.\nOptions are P256, P384 and P521") | ||
flags.Int("size", 2048, "The key size for an RSA key") // TODO(hs): attesting 3072 bit RSA keys on TPM that doesn't support it returns an ugly error; we want to catch that earlier. | ||
flags.Var(alg, "alg", "The hashing `algorithm` to use on RSA PKCS #1 and RSA-PSS signatures.\nOptions are SHA256, SHA384 or SHA512") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably mentioning that this is for tpmkms only or just for new keys. You're also using always PKCS#1 so the RSA-PSS in the help seems unnecessary. We can adding it back if we add support for --new on other KMSs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in bc260c8.
I don't see how I changed the existing logic for the I've changed Is it possible you were testing this with SoftKMS, with an empty So, to conclude, I think |
|
||
# Get a key from the default TPM KMS: | ||
step-kms-plugin key tpmkms:name=my-key | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have a way to export the key to a TSS2 PRIVATE KEY
PEM file, please? And to import them too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added an issue for this: #73. I'm in favor of adding support, but I have a couple other high(er) priority things on my plate to finish first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
I stumbled across RFC7468 today and saw this (penultimate para of p4):
|
This PR adds support for using the TPMKMS with
step-kms-plugin
Attestations for the
tpm
format are created in a slightly different manner than the existing formats. Instead of signing data with the private key, the certification of a key is done at key creation time. The certification facts are recorded in the TPMKMS (in ago.step.sm/crypto/tpm/storage.Store
implementation, actually), so that they can be used by other applications. In this case,step kms attest --format tpm 'tpmkms:name=keyName'
will return an attestation statement that includes these key certification parameters.Will do some more testing and add examples in follow up commits.