On Mon, Apr 6, 2015 at 6:49 PM, Daniel De Graaf <dgde...@tycho.nsa.gov>
wrote:

> On 04/05/2015 07:09 AM, Emil Condrea wrote:
>
>> Enables deep quote execution for vtpmmgr which can not be started
>> using locality 2. The VTPM_ORD_GET_QUOTE command is backwards
>> compatible. When receives flags=0 from vTPM it extends additional
>> information into the PCRs as it did before.
>>
>
> Even without extending values into the resettable PCRs, the PCR
> selection for the quote should not be ignored: otherwise, the
> measurement of the hypervisor (stored in either PCR 4-5 or PCR 18-19)
> cannot be included in a deep quote.  Allowing a guest to attest to the
> measurement of its hypervisor is one of the major reasons for allowing a
> deep quote and is likely to be mandatory in a vTPM provisioning quote.
>
very good point, I missed that someone would include additional PCRs in the
request.

>
> The backwards compatibility added here has some caveats that need to be
> treated carefully.  In the current version, it is not possible to
> distinguish between a request that has the new externData structure and
> a request that uses flags=0 where the vTPM itself has constructed a
> requestData value that looks like a valid externData.
>
> The simplest solution is to always use the structure prepared by the
> vTPM manager for externData and remove backwards compatibility from the
> series.  Since the new quote format would be introduced with a new
> version of the vTPM Manager and (likely) a new hypervisor, any support
> software that makes use of the quotes can be updated at the same time.
>
> If backwards compatibility is needed, then there must be a way to
> distinguish a new-format quote from an old-format quote.  If the reset
> of the modified PCRs is moved to the end of the quote operation (instead
> of the beginning, as is currently done), the value of PCR 20 will be
> at its reset value (either 00..00 or ff..ff) when the new-format quote
> is requested.  Including the value of PCR 20 in all new-format quotes
> would then be sufficient evidence that the externData value in the quote
> was generated by the vTPM Manager.
>
> In addition, it would be useful to add a command-line switch to the vTPM
> manager that disables this backwards compatibility mode if a given
> system will not be using it: this would avoid issues if the users of
> that system have not read this discussion and decide to use quotes that
> do not include PCR 20-23 (which is normally a sensible thing to do).
>
> I think it is reasonable to specify in the documentation the changes and
include only the new version.

>  Flags are interpreted as a bitmask of:
>>   * VTPM_QUOTE_FLAGS_HASH_UUID
>>   * VTPM_QUOTE_FLAGS_VTPM_MEASUREMENTS
>>   * VTPM_QUOTE_FLAGS_GROUP_INFO
>> When using flags!=0, vtpmmgr ignores quoteSelect and TPM_Quote is
>> executed with:
>>    externData = SHA1(
>>     flags,
>>     requestData,
>>     [UUIDs if requested],
>>     [vTPM measurements if requested],
>>     [vTPM group update policy if requested]
>>    )
>>
>
> This specification does not match what you actually do below.  There are
> some advantages to doing it the way you have coded, but the method for
> calculating the hash needs to be fully documented.
>
> I will update the documentation: sha1(UUIDs) instead of UUIDs and so on.

>  Signed-off-by: Emil Condrea <emilcond...@gmail.com>
>> ---
>>
> [...]
>
>  diff --git a/stubdom/vtpmmgr/mgmt_authority.c
>> b/stubdom/vtpmmgr/mgmt_authority.c
>> index 0526a12..0e4aac7 100644
>> --- a/stubdom/vtpmmgr/mgmt_authority.c
>> +++ b/stubdom/vtpmmgr/mgmt_authority.c
>> @@ -128,6 +128,49 @@ static int do_load_aik(struct mem_group *group,
>> TPM_HANDLE *handle)
>>         return TPM_LoadKey(TPM_SRK_KEYHANDLE, &key, handle,
>> (void*)&vtpm_globals.srk_auth, &vtpm_globals.oiap);
>>   }
>>
>> +static void do_vtpminfo_hash(uint32_t extra_info_flags,struct mem_group
>> *group,
>> +       const void* uuid, const uint8_t* kern_hash,unsigned char**
>> calc_hashes)
>> +{
>> +       int i;
>> +       sha1_context ctx;
>> +       if(extra_info_flags & VTPM_QUOTE_FLAGS_HASH_UUID){
>> +               printk("hashing for FLAGS_HASH_UUID: ");
>> +               if(uuid){
>> +                       printk("true");
>> +                       sha1_starts(&ctx);
>> +                       sha1_update(&ctx, (void*)uuid, 16);
>> +                       sha1_finish(&ctx, *calc_hashes);
>> +                       *calc_hashes = *calc_hashes + 20;
>> +               }
>> +               printk("\n");
>> +       }
>> +       if(extra_info_flags & VTPM_QUOTE_FLAGS_VTPM_MEASUREMENTS){
>> +               printk("hashing for VTPM_QUOTE_FLAGS_VTPM_MEASUREMENTS:
>> ");
>> +               if(kern_hash){
>> +                       printk("true");
>> +                       sha1_starts(&ctx);
>> +                       sha1_update(&ctx, (void*)kern_hash, 20);
>> +                       sha1_finish(&ctx, *calc_hashes);
>> +                       *calc_hashes = *calc_hashes + 20;
>> +               }
>> +               printk("\n");
>> +       }
>>
>
> If exactly one of (uuid) and (kern_hash) is NULL and both were requested
> in extra_info_flags, it is not easy to determine which one was used.  A
> better method would be to only place the sha1_update calls inside the
> NULL check and always calculating the SHA1.  This makes interpreting the
> result easier: for a given value of extra_info_flags, the size of the
> externData structure is of constant size.  The presence of the SHA1 of
> the empty string is a sentinel value indicating that the information is
> not available.
>
Indeed. Constant size for externData is a must.

>
>  +       if(extra_info_flags & VTPM_QUOTE_FLAGS_GROUP_INFO){
>> +               printk("hashing for VTPM_QUOTE_FLAGS_GROUP_INFO: true");
>> +               sha1_starts(&ctx);
>> +               sha1_update(&ctx, (void*)&group->id_data.saa_pubkey,
>> sizeof(group->id_data.saa_pubkey));
>> +               sha1_update(&ctx, (void*)&group->details.cfg_seq, 8);
>> +               sha1_update(&ctx, (void*)&group->seal_bits.nr_cfgs, 4);
>> +               for(i=0; i < group->nr_seals; i++)
>> +                       sha1_update(&ctx,
>> (void*)&group->seals[i].digest_release, 20);
>> +               sha1_update(&ctx, (void*)&group->seal_bits.nr_kerns, 4);
>> +               sha1_update(&ctx, (void*)&group->seal_bits.kernels, 20 *
>> be32_native(group->seal_bits.nr_kerns));
>> +               sha1_finish(&ctx, *calc_hashes);
>> +               *calc_hashes = *calc_hashes + 20;
>> +               printk("\n");
>> +       }
>> +}
>>
>
> You should return an error if an unknown bit in extra_info_flags is set;
> this will make it easier to extend the flags later.
>
will do.

>
> One additional flag that would be useful (I can add it later if you don't
> want to add it in the first version):
>
> VTPM_QUOTE_FLAGS_GROUP_PUBKEY - value is SHA1(group->id_data.saa_pubkey).
>         This value does not change when the configuration of a group is
> updated, making it a less informative but more easily verified version of
> VTPM_QUOTE_FLAGS_GROUP_INFO.

I will include it in the next patch series.

>
>
>    /*
>>    * Sets up resettable PCRs for a vTPM deep quote request
>>    */
>> @@ -273,18 +316,44 @@ int group_do_activate(struct mem_group *group,
>> void* blob, int blobSize,
>>
>>   int vtpm_do_quote(struct mem_group *group, const uuid_t uuid,
>>         const uint8_t* kern_hash, const struct tpm_authdata *data,
>> TPM_PCR_SELECTION *sel,
>> -       void* pcr_out, uint32_t *pcr_size, void* sig_out)
>> +       uint32_t extra_info_flags, void* pcr_out, uint32_t *pcr_size,
>> void* sig_out)
>>   {
>>         TPM_HANDLE handle;
>>         TPM_AUTH_SESSION oiap = TPM_AUTH_SESSION_INIT;
>>         TPM_PCR_COMPOSITE pcrs;
>>         BYTE* sig;
>>         UINT32 size;
>> -       int rc;
>> +       sha1_context ctx;
>> +       TPM_DIGEST externData;
>> +       const void* data_to_quote = data;
>> +       UINT32 pcrSelSize = sel->sizeOfSelect;
>> +       unsigned char* ppcr_out = (unsigned char*)pcr_out;
>> +       unsigned char** pcr_outv = (unsigned char**)&ppcr_out;
>>
>> -       rc = do_pcr_setup(group, uuid, kern_hash);
>> -       if (rc)
>> -               return rc;
>> +       int rc;
>> +       if(extra_info_flags == 0){
>> +               printk("Extra Info Flags == 0, hope you are on locality
>> 2\n");
>> +               rc = do_pcr_setup(group, uuid, kern_hash);
>> +               if (rc)
>> +                       return rc;
>> +       }
>> +       else{
>> +               printk("Extra Info Flags =0x%x\n",extra_info_flags);
>> +               //resetting pcr selection
>> +               if(sel->sizeOfSelect > sizeof(sel->pcrSelect))
>> +                       pcrSelSize = sizeof(sel->pcrSelect);
>> +               memset(sel->pcrSelect,0,pcrSelSize);
>> +
>> +               sha1_starts(&ctx);
>> +               sha1_update(&ctx, (void*)&extra_info_flags, 4);
>> +               sha1_update(&ctx, (void*)data, 20);
>> +               do_vtpminfo_hash(extra_info_flags,group, uuid, kern_hash,
>> pcr_outv);
>> +               *pcr_size = *pcr_outv - (unsigned char*)pcr_out;
>>
>
> The values of pcr_out and pcr_size will be NULL when called from
> GroupRegister.
>
I will use an additional pointer if pcr_out is NULL in order to include in
externData
the hash for VTPM_QUOTE_FLAGS_GROUP_INFO if requested.

>
>  +               if(*pcr_size > 0)
>> +                       sha1_update(&ctx, pcr_out, *pcr_size);
>> +               sha1_finish(&ctx, externData.digest);
>> +               data_to_quote = (void*)externData.digest;
>> +       }
>>
>>         rc = do_load_aik(group, &handle);
>>         if (rc)
>> @@ -296,8 +365,7 @@ int vtpm_do_quote(struct mem_group *group, const
>> uuid_t uuid,
>>                 return rc;
>>         }
>>
>> -       rc = TPM_Quote(handle, (void*)data, sel,
>> (void*)&group->aik_authdata, &oiap, &pcrs, &sig, &size);
>> -       printk("TPM_Quote: %d\n", rc);
>> +       rc = TPM_Quote(handle, data_to_quote, sel,
>> (void*)&group->aik_authdata, &oiap, &pcrs, &sig, &size);
>>
>>         TPM_TerminateHandle(oiap.AuthHandle);
>>         TPM_FlushSpecific(handle, TPM_RT_KEY);
>> @@ -310,8 +378,11 @@ int vtpm_do_quote(struct mem_group *group, const
>> uuid_t uuid,
>>         }
>>
>>         if (pcr_out) {
>> -               *pcr_size = pcrs.valueSize;
>> -               memcpy(pcr_out, pcrs.pcrValue, *pcr_size);
>> +               /*hashes already copied when flags!=0 by
>> do_vtpminfo_hash*/
>> +               if(extra_info_flags == 0){
>> +                       *pcr_size = pcrs.valueSize;
>> +                       memcpy(pcr_out, pcrs.pcrValue, *pcr_size);
>> +               }
>>         }
>>
>
> I think it would be useful to append the PCR values to the externData
> values,
> as long as the entire set of hashes doesn't risk becoming too long.
>
Right now the hashes used for externData are written in pcr_out. Should we
limit
the pcr_out size to a certain value?
If there will be a limit for pcr_out, the domU executing the quote will be
able to
read the PCRs for physical TPM using tag TPM_TAG_RQU_COMMAND and
ord TPM_ORD_PcrRead using passthrough, right?
If domU executing the deep quote requests 10 PCRs to be included in the
quote
it will receive in pcr_out just the hashes used for externalData and the
PCR values
should be obtained later.

Now, the maximum hashes number for calculating the externData is 3
( 4 after including VTPM_QUOTE_FLAGS_GROUP_PUBKEY). In the future if
there will be much more hashes we can implement something like
vtpmmgr_GetBootHash for domU clients, so the validation data can be
obtained
with additional requests to vtpmmgr. Is it a good idea?

Also, I have an implementation for requesting a deep quote for trousers and
tpm tools. Do you think it is worth to send patches to those repositories
also, since
TPM_ORD_DeepQuote is not included in the TPM 1.2 specification ?

Thanks for the review!

Emil Condrea


>
> --
> Daniel De Graaf
> National Security Agency
>
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

Reply via email to