if (!tpm2_chip_auth(chip)) {
tpm_buf_append_handle(chip, buf, handle); return;
}
#ifdef CONFIG_TCG_TPM2_HMAC
slot = (tpm_buf_length(buf) - TPM_HEADER_SIZE) / 4; if (slot >= AUTH_MAX_NAMES) {
dev_err(&chip->dev, "TPM: too many handles\n"); return;
}
auth = chip->auth;
WARN(auth->session != tpm_buf_length(buf), "name added in wrong place\n");
tpm_buf_append_u32(buf, handle);
auth->session += 4;
if (mso == TPM2_MSO_PERSISTENT ||
mso == TPM2_MSO_VOLATILE ||
mso == TPM2_MSO_NVRAM) { if (!name)
tpm2_read_public(chip, handle, auth->name[slot]);
} else { if (name)
dev_err(&chip->dev, "TPM: Handle does not require name but one is specified\n");
}
if (auth->session != tpm_buf_length(buf)) { /* we're not the first session */
len = get_unaligned_be32(&buf->data[auth->session]); if (4 + len + auth->session != tpm_buf_length(buf)) {
WARN(1, "session length mismatch, cannot append"); return;
}
/* random number for our nonce */
get_random_bytes(nonce, sizeof(nonce));
memcpy(auth->our_nonce, nonce, sizeof(nonce));
tpm_buf_append_u32(buf, auth->handle); /* our new nonce */
tpm_buf_append_u16(buf, SHA256_DIGEST_SIZE);
tpm_buf_append(buf, nonce, SHA256_DIGEST_SIZE);
tpm_buf_append_u8(buf, auth->attrs); /* and put a placeholder for the hmac */
tpm_buf_append_u16(buf, SHA256_DIGEST_SIZE);
tpm_buf_append(buf, nonce, SHA256_DIGEST_SIZE); #endif
}
EXPORT_SYMBOL_GPL(tpm_buf_append_hmac_session);
/* *justcheckthenames,it'seasytomakemistakes.This *wouldhappenifsomeoneaddedahandlevia *tpm_buf_append_u32()insteadoftpm_buf_append_name()
*/ for (i = 0; i < handles; i++) {
u32 handle = tpm_buf_read_u32(buf, &offset_s);
if (auth->name_h[i] != handle) {
dev_err(&chip->dev, "TPM: handle %d wrong for name\n",
i); return;
}
} /* point offset_s to the start of the sessions */
val = tpm_buf_read_u32(buf, &offset_s); /* point offset_p to the start of the parameters */
offset_p = offset_s + val; for (i = 1; offset_s < offset_p; i++) {
u32 handle = tpm_buf_read_u32(buf, &offset_s);
u16 len;
u8 a;
/* nonce (already in auth) */
len = tpm_buf_read_u16(buf, &offset_s);
offset_s += len;
a = tpm_buf_read_u8(buf, &offset_s);
len = tpm_buf_read_u16(buf, &offset_s); if (handle == auth->handle && auth->attrs == a) {
hmac = &buf->data[offset_s]; /* *saveoursessionnumbersoweknowwhich *sessionintheresponsebelongstous
*/
auth->session = i;
}
offset_s += len;
} if (offset_s != offset_p) {
dev_err(&chip->dev, "TPM session length is incorrect\n"); return;
} if (!hmac) {
dev_err(&chip->dev, "TPM could not find HMAC session\n"); return;
}
/* encrypt before HMAC */ if (auth->attrs & TPM2_SA_DECRYPT) {
u16 len;
/* need key and IV */
tpm2_KDFa(auth->session_key, SHA256_DIGEST_SIZE
+ auth->passphrase_len, "CFB", auth->our_nonce,
auth->tpm_nonce, AES_KEY_BYTES + AES_BLOCK_SIZE,
auth->scratch);
len = tpm_buf_read_u16(buf, &offset_p);
aes_expandkey(&auth->aes_ctx, auth->scratch, AES_KEY_BYTES);
aescfb_encrypt(&auth->aes_ctx, &buf->data[offset_p],
&buf->data[offset_p], len,
auth->scratch + AES_KEY_BYTES); /* reset p to beginning of parameters for HMAC */
offset_p -= 2;
}
sha256_init(&sctx); /* ordinal is already BE */
sha256_update(&sctx, (u8 *)&head->ordinal, sizeof(head->ordinal)); /* add the handle names */ for (i = 0; i < handles; i++) { enum tpm2_mso_type mso = tpm2_handle_mso(auth->name_h[i]);
if (auth->session >= TPM_HEADER_SIZE) {
WARN(1, "tpm session not filled correctly\n"); goto out;
}
if (rc != 0) /* pass non success rc through and close the session */ goto out;
rc = -EINVAL; if (tag != TPM2_ST_SESSIONS) {
dev_err(&chip->dev, "TPM: HMAC response check has no sessions tag\n"); goto out;
}
i = tpm2_find_cc(chip, cc); if (i < 0) goto out;
attrs = chip->cc_attrs_tbl[i];
handles = (attrs >> TPM2_CC_ATTR_RHANDLE) & 1;
/* point to area beyond handles */
offset_s = TPM_HEADER_SIZE + handles * 4;
parm_len = tpm_buf_read_u32(buf, &offset_s);
offset_p = offset_s;
offset_s += parm_len; /* skip over any sessions before ours */ for (i = 0; i < auth->session - 1; i++) {
len = tpm_buf_read_u16(buf, &offset_s);
offset_s += len + 1;
len = tpm_buf_read_u16(buf, &offset_s);
offset_s += len;
} /* TPM nonce */
len = tpm_buf_read_u16(buf, &offset_s); if (offset_s + len > tpm_buf_length(buf)) goto out; if (len != SHA256_DIGEST_SIZE) goto out;
memcpy(auth->tpm_nonce, &buf->data[offset_s], len);
offset_s += len;
attrs = tpm_buf_read_u8(buf, &offset_s);
len = tpm_buf_read_u16(buf, &offset_s); if (offset_s + len != tpm_buf_length(buf)) goto out; if (len != SHA256_DIGEST_SIZE) goto out; /* *offset_spointstotheHMAC.nowcalculatecomparison,beginning *withrphash
*/
sha256_init(&sctx); /* yes, I know this is now zero, but it's what the standard says */
sha256_update(&sctx, (u8 *)&head->return_code, sizeof(head->return_code)); /* ordinal is already BE */
sha256_update(&sctx, (u8 *)&auth->ordinal, sizeof(auth->ordinal));
sha256_update(&sctx, &buf->data[offset_p], parm_len);
sha256_final(&sctx, rphash);
/* now calculate the hmac */
tpm2_hmac_init(&sctx, auth->session_key, sizeof(auth->session_key)
+ auth->passphrase_len);
sha256_update(&sctx, rphash, sizeof(rphash));
sha256_update(&sctx, auth->tpm_nonce, sizeof(auth->tpm_nonce));
sha256_update(&sctx, auth->our_nonce, sizeof(auth->our_nonce));
sha256_update(&sctx, &auth->attrs, 1); /* we're done with the rphash, so put our idea of the hmac there */
tpm2_hmac_final(&sctx, auth->session_key, sizeof(auth->session_key)
+ auth->passphrase_len, rphash); if (memcmp(rphash, &buf->data[offset_s], SHA256_DIGEST_SIZE) == 0) {
rc = 0;
} else {
dev_err(&chip->dev, "TPM: HMAC check failed\n"); goto out;
}
/* now do response decryption */ if (auth->attrs & TPM2_SA_ENCRYPT) { /* need key and IV */
tpm2_KDFa(auth->session_key, SHA256_DIGEST_SIZE
+ auth->passphrase_len, "CFB", auth->tpm_nonce,
auth->our_nonce, AES_KEY_BYTES + AES_BLOCK_SIZE,
auth->scratch);
out: if ((auth->attrs & TPM2_SA_CONTINUE_SESSION) == 0) { if (rc) /* manually close the session if it wasn't consumed */
tpm2_flush_context(chip, auth->handle);
kfree_sensitive(auth);
chip->auth = NULL;
} else { /* reset for next use */
auth->session = TPM_HEADER_SIZE;
}
/* append encrypted salt and squirrel away unencrypted in auth */
tpm_buf_append_salt(&buf, chip, auth); /* session type (HMAC, audit or policy) */
tpm_buf_append_u8(&buf, TPM2_SE_HMAC);
if (param_len + 8 > total_len) return -EINVAL;
len = tpm_buf_read_u16(buf, &offset_r);
offset_t = offset_r; if (name) { /* *nowwehavethepublicarea,computethenameof *theobject
*/
put_unaligned_be16(TPM_ALG_SHA256, name);
sha256(&buf->data[offset_r], len, name + 2);
}
/* validate the public key */
val = tpm_buf_read_u16(buf, &offset_t);
/* key type (must be what we asked for) */ if (val != TPM_ALG_ECC) return -EINVAL;
val = tpm_buf_read_u16(buf, &offset_t);
/* name algorithm */ if (val != TPM_ALG_SHA256) return -EINVAL;
val = tpm_buf_read_u32(buf, &offset_t);
/* object properties */ if (val != TPM2_OA_NULL_KEY) return -EINVAL;
/* auth policy (empty) */
val = tpm_buf_read_u16(buf, &offset_t); if (val != 0) return -EINVAL;
/* symmetric key parameters */
val = tpm_buf_read_u16(buf, &offset_t); if (val != TPM_ALG_AES) return -EINVAL;
/* symmetric key length */
val = tpm_buf_read_u16(buf, &offset_t); if (val != AES_KEY_BITS) return -EINVAL;
/* symmetric encryption scheme */
val = tpm_buf_read_u16(buf, &offset_t); if (val != TPM_ALG_CFB) return -EINVAL;
/* signing scheme */
val = tpm_buf_read_u16(buf, &offset_t); if (val != TPM_ALG_NULL) return -EINVAL;
/* ECC Curve */
val = tpm_buf_read_u16(buf, &offset_t); if (val != TPM2_ECC_NIST_P256) return -EINVAL;
/* KDF Scheme */
val = tpm_buf_read_u16(buf, &offset_t); if (val != TPM_ALG_NULL) return -EINVAL;
/* extract public key (x and y points) */
val = tpm_buf_read_u16(buf, &offset_t); if (val != EC_PT_SZ) return -EINVAL;
memcpy(chip->null_ec_key_x, &buf->data[offset_t], val);
offset_t += val;
val = tpm_buf_read_u16(buf, &offset_t); if (val != EC_PT_SZ) return -EINVAL;
memcpy(chip->null_ec_key_y, &buf->data[offset_t], val);
offset_t += val;
/* original length of the whole TPM2B */
offset_r += len;
/* should have exactly consumed the TPM2B public structure */ if (offset_t != offset_r) return -EINVAL; if (offset_r > param_len) return -EINVAL;
/* creation data (skip) */
len = tpm_buf_read_u16(buf, &offset_r);
offset_r += len; if (offset_r > param_len) return -EINVAL;
/* creation digest (must be sha256) */
len = tpm_buf_read_u16(buf, &offset_r);
offset_r += len;
if (len != SHA256_DIGEST_SIZE || offset_r > param_len)
return -EINVAL;
/* TPMT_TK_CREATION follows */
/* tag, must be TPM_ST_CREATION (0x8021) */
val = tpm_buf_read_u16(buf, &offset_r);
if (val != TPM2_ST_CREATION || offset_r > param_len)
return -EINVAL;
/* hierarchy */
val = tpm_buf_read_u32(buf, &offset_r);
if (val != hierarchy || offset_r > param_len)
return -EINVAL;
/* the ticket digest HMAC (might not be sha256) */
len = tpm_buf_read_u16(buf, &offset_r);
offset_r += len;
if (offset_r > param_len)
return -EINVAL;
/*
* finally we have the name, which is a sha256 digest plus a 2
* byte algorithm type
*/
len = tpm_buf_read_u16(buf, &offset_r);
if (offset_r + len != param_len + 8)
return -EINVAL;
if (len != SHA256_DIGEST_SIZE + 2)
return -EINVAL;
if (memcmp(chip->null_key_name, &buf->data[offset_r],
SHA256_DIGEST_SIZE + 2) != 0) {
dev_err(&chip->dev, "NULL Seed name comparison failed\n");
return -EINVAL;
}
return 0;
}
/**
* tpm2_create_primary() - create a primary key using a fixed P-256 template
*
* @chip: the TPM chip to create under
* @hierarchy: The hierarchy handle to create under
* @handle: The returned volatile handle on success
* @name: The name of the returned key
*
* For platforms that might not have a persistent primary, this can be
* used to create one quickly on the fly (it uses Elliptic Curve not
* RSA, so even slow TPMs can create one fast). The template uses the
* TCG mandated H one for non-endorsement ECC primaries, i.e. P-256
* elliptic curve (the only current one all TPM2s are required to
* have) a sha256 name hash and no policy.
*
* Return:
* * 0 - OK
* * -errno - A system error
* * TPM_RC - A TPM error
*/
static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
u32 *handle, u8 *name)
{
int rc;
struct tpm_buf buf;
struct tpm_buf template;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE_PRIMARY);
if (rc)
return rc;
rc = tpm_buf_init_sized(&template);
if (rc) {
tpm_buf_destroy(&buf);
return rc;
}
/*
* create the template. Note: in order for userspace to
* verify the security of the system, it will have to create
* and certify this NULL primary, meaning all the template
* parameters will have to be identical, so conform exactly to
* the TCG TPM v2.0 Provisioning Guidance for the SRK ECC
* key H template (H has zero size unique points)
*/
/* key type */
tpm_buf_append_u16(&template, TPM_ALG_ECC);
/* name algorithm */
tpm_buf_append_u16(&template, TPM_ALG_SHA256);
/**
* tpm2_sessions_init() - start of day initialization for the sessions code
* @chip: TPM chip
*
* Derive and context save the null primary and allocate memory in the
* struct tpm_chip for the authorizations.
*
* Return:
* * 0 - OK
* * -errno - A system error
* * TPM_RC - A TPM error
*/
int tpm2_sessions_init(struct tpm_chip *chip)
{
int rc;
rc = tpm2_create_null_primary(chip);
if (rc) {
dev_err(&chip->dev, "null key creation failed with %d\n", rc);
return rc;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.