tpm2-tools icon indicating copy to clipboard operation
tpm2-tools copied to clipboard

tpm2_certify counter value bug?

Open SchermannR opened this issue 2 years ago • 2 comments

I tried to certify a key with an eccdaa sign key. This worked at the initial run and after a reset. However, imho the problem seems to be that I cannot specify a counter value like in the sign operation with --commit-index. For a simple sign with an eccdaa key it works when i put the actual counter value in this argument.

SchermannR avatar Aug 17 '22 15:08 SchermannR

I fixed the code - maybe you can reuse it. The code changes are marked with /fix SchermannR/ and /* end fix*/ Cheers Raphael

`/* SPDX-License-Identifier: BSD-3-Clause */

#include <stdlib.h>

#include "files.h" #include "log.h" #include "tpm2.h" #include "tpm2_tool.h" #include "tpm2_alg_util.h" #include "tpm2_convert.h" #include "tpm2_options.h"

typedef struct tpm_certify_ctx tpm_certify_ctx; #define MAX_AUX_SESSIONS 1 // two sessions provided by auth interface #define MAX_SESSIONS 3 struct tpm_certify_ctx { /* * Inputs */ struct { const char *ctx_path; const char *auth_str; tpm2_loaded_object object; } certified_key;

struct {
    const char *ctx_path;
    const char *auth_str;
    tpm2_loaded_object object;
} signing_key;

TPMI_ALG_HASH halg;
tpm2_convert_sig_fmt sig_fmt;
TPMT_SIG_SCHEME scheme;
TPMI_ALG_SIG_SCHEME sig_scheme;

/* fix SchermannR */
char *commit_index;
/* end fix */
/*
 * Outputs
*/
struct {
    char *attest;
    char *sig;
} file_path;
TPM2B_ATTEST *certify_info;
TPMT_SIGNATURE *signature;

/*
 * Parameter hashes
 */
const char *cp_hash_path;
TPM2B_DIGEST cp_hash;
const char *rp_hash_path;
TPM2B_DIGEST rp_hash;
bool is_command_dispatch;
TPMI_ALG_HASH parameter_hash_algorithm;

/*
 * Aux sessions
 */
uint8_t aux_session_cnt;
tpm2_session *aux_session[MAX_AUX_SESSIONS];
const char *aux_session_path[MAX_AUX_SESSIONS];
ESYS_TR aux_session_handle[MAX_AUX_SESSIONS];

};

static tpm_certify_ctx ctx = { .sig_fmt = signature_format_tss, .halg = TPM2_ALG_NULL, .sig_scheme = TPM2_ALG_NULL, .aux_session_handle[0] = ESYS_TR_NONE, .parameter_hash_algorithm = TPM2_ALG_ERROR, .scheme = { .scheme = TPM2_ALG_NULL, } };

static tool_rc certify(ESYS_CONTEXT *ectx) {

TPM2B_DATA qualifying_data = {
    .size = 4,
    .buffer = { 0x00, 0xff, 0x55,0xaa },
};

/*
 * 1. TPM2_CC_<command> OR Retrieve cpHash
 */

return tpm2_certify(ectx, &ctx.certified_key.object,
    &ctx.signing_key.object, &qualifying_data, &ctx.scheme,
    &ctx.certify_info, &ctx.signature, &ctx.cp_hash, &ctx.rp_hash,
    ctx.parameter_hash_algorithm, ctx.aux_session_handle[0]);

}

static tool_rc process_output(ESYS_CONTEXT *ectx) {

UNUSED(ectx);

/*
 * 1. Outputs that do not require TPM2_CC_<command> dispatch
 */
bool is_file_op_success = true;
if (ctx.cp_hash_path) {
    is_file_op_success = files_save_digest(&ctx.cp_hash, ctx.cp_hash_path);

    if (!is_file_op_success) {
        return tool_rc_general_error;
    }
}

if (!ctx.is_command_dispatch) {
    return tool_rc_success;
}
/*
 * 2. Outputs generated after TPM2_CC_<command> dispatch
 */
/* serialization is safe here, since it's just a byte array */
is_file_op_success = files_save_bytes_to_file(ctx.file_path.attest,
    ctx.certify_info->attestationData, ctx.certify_info->size);
if (!is_file_op_success) {
     goto out;
 }

is_file_op_success = tpm2_convert_sig_save(ctx.signature, ctx.sig_fmt,
    ctx.file_path.sig);
if (!is_file_op_success) {
    goto out;
}

if (ctx.rp_hash_path) {
    is_file_op_success = files_save_digest(&ctx.rp_hash, ctx.rp_hash_path);
}

out: free(ctx.certify_info); free(ctx.signature);

return is_file_op_success ? tool_rc_success : tool_rc_general_error;

}

static tool_rc process_inputs(ESYS_CONTEXT *ectx) {

/*
 * 1. Object and auth initializations
 */

/*
 * 1.a Add the new-auth values to be set for the object.
 */

/*
 * 1.b Add object names and their auth sessions
 */
/* Object #1 */
tool_rc rc = tpm2_util_object_load_auth(ectx, ctx.certified_key.ctx_path,
    ctx.certified_key.auth_str, &ctx.certified_key.object, false,
    TPM2_HANDLE_ALL_W_NV);
if (rc != tool_rc_success) {
    return rc;
}

/* Object #2 */
rc = tpm2_util_object_load_auth(ectx, ctx.signing_key.ctx_path,
    ctx.signing_key.auth_str, &ctx.signing_key.object, false,
    TPM2_HANDLE_ALL_W_NV);
if (rc != tool_rc_success) {
    return rc;
}

/*
 * 2. Restore auxiliary sessions
 */
rc = tpm2_util_aux_sessions_setup(ectx, ctx.aux_session_cnt,
    ctx.aux_session_path, ctx.aux_session_handle, ctx.aux_session);
if (rc != tool_rc_success) {
    return rc;
}

/*
 * 3. Command specific initializations
 */

rc = tpm2_alg_util_get_signature_scheme(ectx,
    ctx.signing_key.object.tr_handle, &ctx.halg, ctx.sig_scheme,
    &ctx.scheme);
if (rc != tool_rc_success) {
    return rc;
}
/*fix SchermannR*/
if (ctx.scheme.scheme != TPM2_ALG_ECDAA && ctx.commit_index) {
    LOG_ERR("Commit counter is only applicable in an ECDAA scheme.");
    return tool_rc_option_error;
}

if (ctx.scheme.scheme == TPM2_ALG_ECDAA && ctx.commit_index) {
    bool result = tpm2_util_string_to_uint16(ctx.commit_index,
        &ctx.scheme.details.ecdaa.count);
    if (!result) {
        return tool_rc_general_error;
    }
}
/* end fix */
/*
 * 4. Configuration for calculating the pHash
 */

/*
 * 4.a Determine pHash length and alg
 */
tpm2_session *all_sessions[MAX_SESSIONS] = {
    ctx.certified_key.object.session,
    ctx.signing_key.object.session,
    ctx.aux_session[0]
};

const char **cphash_path = ctx.cp_hash_path ? &ctx.cp_hash_path : 0;
const char **rphash_path = ctx.rp_hash_path ? &ctx.rp_hash_path : 0;

ctx.parameter_hash_algorithm = tpm2_util_calculate_phash_algorithm(ectx,
    cphash_path, &ctx.cp_hash, rphash_path, &ctx.rp_hash, all_sessions);

/*
 * 4.b Determine if TPM2_CC_<command> is to be dispatched
 * !rphash && !cphash [Y]
 * !rphash && cphash  [N]
 * rphash && !cphash  [Y]
 * rphash && cphash   [Y]
 */
ctx.is_command_dispatch = (ctx.cp_hash_path && !ctx.rp_hash_path) ?
    false : true;

return rc;

}

static tool_rc check_options(void) {

if ((!ctx.certified_key.ctx_path) && (!ctx.signing_key.ctx_path)) {
    LOG_ERR("Must specify the object to be certified and the signing key.");
    return tool_rc_option_error;
}

if (ctx.cp_hash_path && !ctx.rp_hash_path &&
   (ctx.file_path.attest || ctx.file_path.sig)) {
    LOG_ERR("Cannot specify output options when calculating cpHash");
    return tool_rc_option_error;
}
/*fix SchermannR*/
if(ctx.commit_index){
    bool result = tpm2_util_string_to_uint16(ctx.commit_index,&ctx.scheme.details.ecdaa.count);
    if(!result){
        return tool_rc_general_error;
    }
    
}
/* end fix */
return tool_rc_success;

}

static bool on_option(char key, char *value) {

switch (key) {
case 'c':
    ctx.certified_key.ctx_path = value;
    break;
case 'C':
    ctx.signing_key.ctx_path = value;
    break;
case 'P':
    ctx.certified_key.auth_str = value;
    break;
case 'p':
    ctx.signing_key.auth_str = value;
    break;
case 'g':
    ctx.halg = tpm2_alg_util_from_optarg(value, tpm2_alg_util_flags_hash);
    if (ctx.halg == TPM2_ALG_ERROR) {
        LOG_ERR("Could not format algorithm to number, got: \"%s\"", value);
        return false;
    }
    break;
case 'o':
    ctx.file_path.attest = value;
    break;
case 's':
    ctx.file_path.sig = value;
    break;
case 0:
    ctx.cp_hash_path = value;
    break;
case 1:
    ctx.rp_hash_path = value;
    break;
case 2:
    ctx.sig_scheme = tpm2_alg_util_from_optarg(value,
            tpm2_alg_util_flags_sig);
    if (ctx.sig_scheme == TPM2_ALG_ERROR) {
        LOG_ERR("Unknown signing scheme, got: \"%s\"", value);
        return false;
    }
    break;
/*fix SchermannR*/
case 3: 
    ctx.commit_index = value;
    break;
/* end fix */
case 'f':
    ctx.sig_fmt = tpm2_convert_sig_fmt_from_optarg(value);
    if (ctx.sig_fmt == signature_format_err) {
        return false;
    }
    break;
case 'S':
    ctx.aux_session_path[ctx.aux_session_cnt] = value;
    if (ctx.aux_session_cnt < MAX_AUX_SESSIONS) {
        ctx.aux_session_cnt++;
    } else {
        LOG_ERR("Specify a max of 3 sessions");
        return false;
    }
    break;
}


return true;

}

static bool tpm2_tool_onstart(tpm2_options **opts) {

const struct option topts[] = {
  { "certifiedkey-context", required_argument, NULL, 'c' },
  { "signingkey-context",   required_argument, NULL, 'C' },
  { "certifiedkey-auth",    required_argument, NULL, 'p' },
  { "signingkey-auth",      required_argument, NULL, 'P' },
  { "hash-algorithm",       required_argument, NULL, 'g' },
  { "attestation",          required_argument, NULL, 'o' },
  { "signature",            required_argument, NULL, 's' },
  { "format",               required_argument, NULL, 'f' },
  { "cphash",               required_argument, NULL,  0  },
  { "rphash",               required_argument, NULL,  1  },
  { "scheme",               required_argument, NULL,  2  },
  { "session",              required_argument, NULL, 'S' },
  /*fix SchermannR*/
  { "commit-index",         required_argument, 0,  3  },
  /* end fix */
};

*opts = tpm2_options_new("P:p:g:o:s:c:C:f:S:", ARRAY_LEN(topts), topts,
        on_option, NULL, 0);

return *opts != NULL;

}

static tool_rc tpm2_tool_onrun(ESYS_CONTEXT *ectx, tpm2_option_flags flags) {

UNUSED(flags);

/*
 * 1. Process options
 */
tool_rc rc = check_options();
if (rc != tool_rc_success) {
    return rc;
}

/*
 * 2. Process inputs
 */
rc = process_inputs(ectx);
if (rc != tool_rc_success) {
    return rc;
}

/*
 * 3. TPM2_CC_<command> call
 */
rc = certify(ectx);
if (rc != tool_rc_success) {
    return rc;
}

/*
 * 4. Process outputs
 */
return process_output(ectx);

}

static tool_rc tpm2_tool_onstop(ESYS_CONTEXT *ectx) {

UNUSED(ectx);

/*
 * 1. Free objects
 */

/*
 * 2. Close authorization sessions
 */
tool_rc rc = tool_rc_success;
tool_rc tmp_rc = tpm2_session_close(&ctx.signing_key.object.session);
if (tmp_rc != tool_rc_success) {
    rc = tmp_rc;
}

tmp_rc = tpm2_session_close(&ctx.certified_key.object.session);
if (tmp_rc != tool_rc_success) {
    rc = tmp_rc;
}

/*
 * 3. Close auxiliary sessions
 */
size_t i = 0;
for(i = 0; i < ctx.aux_session_cnt; i++) {
    if (ctx.aux_session_path[i]) {
        tmp_rc = tpm2_session_close(&ctx.aux_session[i]);
        if (tmp_rc != tool_rc_success) {
            rc = tmp_rc;
        }
    }
}

return rc;

}

// Register this tool with tpm2_tool.c TPM2_TOOL_REGISTER("certify", tpm2_tool_onstart, tpm2_tool_onrun, tpm2_tool_onstop, NULL) `

SchermannR avatar Aug 18 '22 18:08 SchermannR

@SchermannR Thank you for finding the missing feature and providing a fix.

idesai avatar Aug 22 '22 20:08 idesai