Open mdempsky opened 5 years ago
Thanks for the code! I'd be interested in getting this in via a PR if theres appetite, ECC AKs would be great to support.
The original intent behind passing a crypto.Public + symBlockSize was that credential activation would be done on the server, where building into tpm2.Public for the EK would be onerous and (in the case of windows, not all those details would be available).
Which places are the wrong NameAlg being used?
Thanks for the code! I'd be interested in getting this in via a PR if theres appetite, ECC AKs would be great to support.
Okay, I'll work on a PR this week.
The original intent behind passing a crypto.Public + symBlockSize was that credential activation would be done on the server, where building into tpm2.Public for the EK would be onerous and (in the case of windows, not all those details would be available).
Can you elaborate? The client already has to send their AK's TPM2B_PUBLIC to the server, so it doesn't seem onerous to send the EK's TPM2B_PUBLIC as well.
However, if there are existing protocols that only send the bare EK public key (e.g., the client only sends its EK's X.509 key certificate) and we want to easily support those, I'd probably design the API like:
// Low-level credential protection primitive.
func Protect(ekNameAlg tpm2.NameAlg, ekPub crypto.PublicKey, ekSym *tpm2.SymScheme, ...) {
// Above code.
}
// User friendly interface that supports arbitrary EKs.
func ProtectPublic(ek *tpm2.Public, ...) {
pub, err := ek.Key()
if err != nil {
return ..., err
}
switch pub.(type) {
case *rsa.PublicKey:
return Protect(ek.NameAlg, pub, ek.RSAParameters.Symmetric, ...)
case *ecdsa.PublicKey:
return Protect(ek.NameAlg, pub, ek.ECCParameters.Symmetric, ...)
}
return ..., errors.New(...)
}
// ProtectDefault assumes ekPub was generated using a default EK template
// defined by "TCG EK Credential Profile For TPM Family 2.0".
func ProtectDefault(ekPub crypto.PublicKey, ...) {
switch ekPub := ekPub.(type) {
case *rsa.PublicKey:
switch ekPub.Size() * 8 {
case 2048: // Templates L-1 and H-1
return Protect(tpm2.AlgSHA256, ekPub, symAESCFB128, ...)
}
case *ecdsa.PublicKey:
switch ekPub.Params().Name {
case "P-256": // Templates L-2 and H-2
return Protect(tpm2.AlgSHA256, ekPub, symAESCFB128, ...)
case "P-384": // Template H-3
return Protect(tpm2.AlgSHA384, ekPub, symAESCFB256, ...)
case "P-521": // Template H-4
return Protect(tpm2.AlgSHA512, ekPub, symAESCFB256, ...)
}
}
return ..., errors.New(...)
}
var symAESCFB128 = &tpm2.Symmetric{tpm2.AlgAES, 128, tpm2.AlgCFB}
var symAESCFB256 = &tpm2.Symmetric{tpm2.AlgAES, 256, tpm2.AlgCFB}
Which places are the wrong NameAlg being used?
Everywhere that aik.Alg
is mentioned at https://github.com/google/go-tpm/blob/master/tpm2/credactivation/credential_activation.go.
The AK's NameAlg is only needed for hashing the AK's Public structure into its Name. Everything else (i.e., the RSA/ECC key-exchange, the AES and HMAC KDF computations, and the underlying hash used with the HMAC) should use the EK's NameAlg instead.
Trusted Platform Module Library, Part 1: Architecture, Sections 24.4 and 24.5 directly mention "ekNameAlg" for all of the symmetric key operations.
The use of the EK's public key for the RSA/ECC key-exchange is less explicitly worded; but it's a consequence of using RSA Secret Sharing (section B.10) or ECC Secret Sharing (section C.6), and in context their mentions of "nameAlg" refer to the key that the secret is being shared with (which is the EK; see section 24.2, "and then 'wraps' the credential encryption key with the public key of the 'EK.'").
Can you elaborate? The client already has to send their AK's TPM2B_PUBLIC to the server, so it doesn't seem onerous to send the EK's TPM2B_PUBLIC as well.
On windows + using the platform crypto provider, we dont get a direct channel to the TPM that is authorized for the EK. As such, we use other APIs to read the public details of the EK, but we can cant get a TPM2B_PUBLIC
for the EK. There is a way to get the AK's TPM2B_PUBLIC
however.
Now that I think about it though, the template for the windows EK is well defined + fixed to this, so maybe in the windows case we can just fill in a tpm2.Public
manually?
On windows + using the platform crypto provider, we dont get a direct channel to the TPM that is authorized for the EK.
I see. Thanks, I'm not familiar with Windows's TPM APIs.
Now that I think about it though, the template for the windows EK is well defined + fixed to this, so maybe in the windows case we can just fill in a tpm2.Public manually?
Windows only supports the Template L-1 EK profile? It doesn't even support ECC EKs?
Either way, if you only have the EK's public key, you can reconstruct the important parts of the EK's TPM2B_PUBLIC; in particular, the nameAlg and parameters.symmetric fields.
As a minor nit though, you can't distinguish Template L-1 from H-1, or L-2 from H-2, based on public key alone. So you wouldn't be able to reconstruct objectAttributes, authPolicy, or unique without extra information. This is why I suggested ProtectDefault
above.
Windows only supports the Template L-1 EK profile? It doesn't even support ECC EKs?
I'm unsure if ECC EKs are specified, but they are not required. Windows 8/10+ requires:
Either way, if you only have the EK's public key, you can reconstruct the important parts of the EK's TPM2B_PUBLIC; in particular, the nameAlg and parameters.symmetric fields.
As a minor nit though, you can't distinguish Template L-1 from H-1, or L-2 from H-2, based on public key alone. So you wouldn't be able to reconstruct objectAttributes, authPolicy, or unique without extra information. This is why I suggested ProtectDefault above.
Given the EK is well specified on windows, I think filling in the missing fields would work fine. As such, I'm okay with either (ProtectDefault
or passing tpm2.Public
) approach.
Heya, just wondering if you had any update on this?
credactivation.Generate uses the AK's NameAlg in a bunch of places, but it should be using the EK's.
I've experimentally verified that this causes problems using tpm2-tools's tpm2_activatecredential tool with an AK that uses SHA1 as its name algorithm.
Incidentally, I think having the API require the user to provide symBlockSize is unnecessarily awkward. Instead, just have them provide the EK as a
tpm2.Public
, and then you can pick out the NameAlg and symmetric cipher specs automatically.Finally, I was interested in supporting ECC endorsement keys, so I implemented KDFe and support for generating an ECC seed.
Code is still hacky and proof-of-concept-y, but I've experimentally verified that it works with {RSA2048, ECC-P256} x {SHA1, SHA256} EKs on my workstation's TPM2. I plan to eventually try it against Microsoft's TPM simulator so I can test larger RSA/ECC keys.
In tpm2/kdf.go: