uint32_t TPM_CreateMigrationBlob(unsigned int keyhandle, unsigned char *keyauth, unsigned char *migauth, int migtype, unsigned char *migblob, unsigned int migblen, unsigned char *keyblob, unsigned int keyblen, unsigned char *rndblob, unsigned int *rndblen, unsigned char *outblob, unsigned int *outblen) { unsigned char create_mig_fmt[] = "00 c3 T l l s % @ l % o % l % o %"; unsigned char create_mig_fmt_noauth[] = "00 c2 T l l s % @ l % o %"; uint32_t ret; unsigned char tpmdata[TPM_MAX_BUFF_SIZE]; unsigned char nonceodd[TPM_NONCE_SIZE]; unsigned char enonce1[TPM_NONCE_SIZE]; unsigned char enonce2[TPM_NONCE_SIZE]; unsigned char c; uint32_t ordinal; uint32_t keyhndl; uint32_t datsize; uint16_t migscheme; uint32_t authhandle1; uint32_t authhandle2; unsigned char authdata1[TPM_HASH_SIZE]; unsigned char authdata2[TPM_HASH_SIZE]; uint32_t size1; uint32_t size2; keydata k; /* check input arguments */ if (migauth == NULL || migblob == NULL || keyblob == NULL) return ERR_NULL_ARG; if (rndblob == NULL || rndblen == NULL || outblob == NULL || outblen == NULL) return ERR_NULL_ARG; if (migtype != 1 && migtype != 2) return ERR_BAD_ARG; TSS_KeyExtract(keyblob, &k); /* move data to Network byte order variables for HMAC calculation */ ordinal = htonl(0x28); keyhndl = htonl(keyhandle); migscheme = htons(migtype); datsize = htonl(k.privkeylen); /* generate odd nonce */ TSS_gennonce(nonceodd); c = 0; if (keyauth != NULL) { /* parent key password is required */ /* open TWO OIAP sessions: Parent and Migrating Key */ ret = TSS_OIAPopen(&authhandle1, enonce1); if (ret != 0) return ret; ret = TSS_OIAPopen(&authhandle2, enonce2); if (ret != 0) return ret; /* calculate Parent KEY authorization HMAC value */ ret = TSS_authhmac(authdata1, keyauth, TPM_HASH_SIZE, enonce1, nonceodd, c, TPM_U32_SIZE, &ordinal, TPM_U16_SIZE, &migscheme, migblen, migblob, TPM_U32_SIZE, &datsize, k.privkeylen, k.encprivkey, 0, 0); if (ret != 0) { TSS_OIAPclose(authhandle1); TSS_OIAPclose(authhandle2); return ret; } /* calculate Migration authorization HMAC value */ ret = TSS_authhmac(authdata2, migauth, TPM_HASH_SIZE, enonce2, nonceodd, c, TPM_U32_SIZE, &ordinal, TPM_U16_SIZE, &migscheme, migblen, migblob, TPM_U32_SIZE, &datsize, k.privkeylen, k.encprivkey, 0, 0); if (ret != 0) { TSS_OIAPclose(authhandle1); TSS_OIAPclose(authhandle2); return ret; } /* build the request buffer */ ret = TSS_buildbuff(create_mig_fmt, tpmdata, ordinal, keyhndl, migscheme, migblen, migblob, k.privkeylen, k.encprivkey, authhandle1, TPM_NONCE_SIZE, nonceodd, c, TPM_HASH_SIZE, authdata1, authhandle2, TPM_NONCE_SIZE, nonceodd, c, TPM_HASH_SIZE, authdata2); if ((ret & ERR_MASK) != 0) { TSS_OIAPclose(authhandle1); TSS_OIAPclose(authhandle2); return ret; } /* transmit buffer to the TPM device and read the reply */ ret = TPM_Transmit(tpmdata, "CreateMigrationBlob"); if (ret != 0) { TSS_OIAPclose(authhandle1); TSS_OIAPclose(authhandle2); return ret; } /* validate HMAC in response */ size1 = LOAD32(tpmdata, TPM_DATA_OFFSET); size2 = LOAD32(tpmdata, TPM_DATA_OFFSET + TPM_U32_SIZE + size1); if (size1 != 0) { ret = TSS_checkhmac2(tpmdata, ordinal, nonceodd, keyauth, TPM_HASH_SIZE, migauth, TPM_HASH_SIZE, TPM_U32_SIZE, TPM_DATA_OFFSET, size1, TPM_DATA_OFFSET + TPM_U32_SIZE, TPM_U32_SIZE, TPM_DATA_OFFSET + TPM_U32_SIZE + size1, size2, TPM_DATA_OFFSET + TPM_U32_SIZE + size1 + TPM_U32_SIZE, 0, 0); } else { ret = TSS_checkhmac2(tpmdata, ordinal, nonceodd, keyauth, TPM_HASH_SIZE, migauth, TPM_HASH_SIZE, TPM_U32_SIZE, TPM_DATA_OFFSET, TPM_U32_SIZE, TPM_DATA_OFFSET + TPM_U32_SIZE, size2, TPM_DATA_OFFSET + TPM_U32_SIZE + TPM_U32_SIZE, 0, 0); } TSS_OIAPclose(authhandle1); TSS_OIAPclose(authhandle2); if (ret != 0) return ret; } else { /* no parent key password required */ /* open OIAP session for the Migrating Key */ ret = TSS_OIAPopen(&authhandle1, enonce1); if (ret != 0) return ret; /* calculate Migration authorization HMAC value */ ret = TSS_authhmac(authdata1, migauth, TPM_HASH_SIZE, enonce1, nonceodd, c, TPM_U32_SIZE, &ordinal, TPM_U16_SIZE, &migscheme, migblen, migblob, TPM_U32_SIZE, &datsize, k.privkeylen, k.encprivkey, 0, 0); if (ret != 0) { TSS_OIAPclose(authhandle1); return ret; } /* build the request buffer */ ret = TSS_buildbuff(create_mig_fmt_noauth, tpmdata, ordinal, keyhndl, migscheme, migblen, migblob, k.privkeylen, k.encprivkey, authhandle1, TPM_NONCE_SIZE, nonceodd, c, TPM_HASH_SIZE, authdata1); if ((ret & ERR_MASK) != 0) { TSS_OIAPclose(authhandle1); return ret; } /* transmit buffer to the TPM device and read the reply */ ret = TPM_Transmit(tpmdata, "CreateMigrationBlob"); if (ret != 0) { TSS_OIAPclose(authhandle1); return ret; } /* check HMAC in response */ size1 = LOAD32(tpmdata, TPM_DATA_OFFSET); size2 = LOAD32(tpmdata, TPM_DATA_OFFSET + TPM_U32_SIZE + size1); if (size1 != 0) { ret = TSS_checkhmac1(tpmdata, ordinal, nonceodd, migauth, TPM_HASH_SIZE, TPM_U32_SIZE, TPM_DATA_OFFSET, size1, TPM_DATA_OFFSET + TPM_U32_SIZE, TPM_U32_SIZE, TPM_DATA_OFFSET + TPM_U32_SIZE + size1, size2, TPM_DATA_OFFSET + TPM_U32_SIZE + size1 + TPM_U32_SIZE, 0, 0); } else { ret = TSS_checkhmac1(tpmdata, ordinal, nonceodd, migauth, TPM_HASH_SIZE, TPM_U32_SIZE, TPM_DATA_OFFSET, TPM_U32_SIZE, TPM_DATA_OFFSET + TPM_U32_SIZE, size2, TPM_DATA_OFFSET + TPM_U32_SIZE + TPM_U32_SIZE, 0, 0); } TSS_OIAPclose(authhandle1); if (ret != 0) return ret; } memcpy(rndblob, tpmdata + TPM_DATA_OFFSET + TPM_U32_SIZE, size1); memcpy(outblob, tpmdata + TPM_DATA_OFFSET + TPM_U32_SIZE + size1 + TPM_U32_SIZE, size2); *rndblen = size1; *outblen = size2; return 0; }
/* * use the AUTH2_COMMAND form of unseal, to authorize both key and blob */ static int tpm_unseal(struct tpm_buf *tb, uint32_t keyhandle, const unsigned char *keyauth, const unsigned char *blob, int bloblen, const unsigned char *blobauth, unsigned char *data, unsigned int *datalen) { unsigned char nonceodd[TPM_NONCE_SIZE]; unsigned char enonce1[TPM_NONCE_SIZE]; unsigned char enonce2[TPM_NONCE_SIZE]; unsigned char authdata1[SHA1_DIGEST_SIZE]; unsigned char authdata2[SHA1_DIGEST_SIZE]; uint32_t authhandle1 = 0; uint32_t authhandle2 = 0; unsigned char cont = 0; uint32_t ordinal; uint32_t keyhndl; int ret; /* sessions for unsealing key and data */ ret = oiap(tb, &authhandle1, enonce1); if (ret < 0) { pr_info("trusted_key: oiap failed (%d)\n", ret); return ret; } ret = oiap(tb, &authhandle2, enonce2); if (ret < 0) { pr_info("trusted_key: oiap failed (%d)\n", ret); return ret; } ordinal = htonl(TPM_ORD_UNSEAL); keyhndl = htonl(SRKHANDLE); ret = tpm_get_random(TPM_ANY_NUM, nonceodd, TPM_NONCE_SIZE); if (ret != TPM_NONCE_SIZE) { pr_info("trusted_key: tpm_get_random failed (%d)\n", ret); return ret; } ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE, enonce1, nonceodd, cont, sizeof(uint32_t), &ordinal, bloblen, blob, 0, 0); if (ret < 0) return ret; ret = TSS_authhmac(authdata2, blobauth, TPM_NONCE_SIZE, enonce2, nonceodd, cont, sizeof(uint32_t), &ordinal, bloblen, blob, 0, 0); if (ret < 0) return ret; /* build and send TPM request packet */ INIT_BUF(tb); store16(tb, TPM_TAG_RQU_AUTH2_COMMAND); store32(tb, TPM_UNSEAL_SIZE + bloblen); store32(tb, TPM_ORD_UNSEAL); store32(tb, keyhandle); storebytes(tb, blob, bloblen); store32(tb, authhandle1); storebytes(tb, nonceodd, TPM_NONCE_SIZE); store8(tb, cont); storebytes(tb, authdata1, SHA1_DIGEST_SIZE); store32(tb, authhandle2); storebytes(tb, nonceodd, TPM_NONCE_SIZE); store8(tb, cont); storebytes(tb, authdata2, SHA1_DIGEST_SIZE); ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); if (ret < 0) { pr_info("trusted_key: authhmac failed (%d)\n", ret); return ret; } *datalen = LOAD32(tb->data, TPM_DATA_OFFSET); ret = TSS_checkhmac2(tb->data, ordinal, nonceodd, keyauth, SHA1_DIGEST_SIZE, blobauth, SHA1_DIGEST_SIZE, sizeof(uint32_t), TPM_DATA_OFFSET, *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0, 0); if (ret < 0) { pr_info("trusted_key: TSS_checkhmac2 failed (%d)\n", ret); return ret; } memcpy(data, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *datalen); return 0; }
uint32_t TPM_Unseal(uint32_t keyhandle, unsigned char *keyauth, unsigned char *dataauth, unsigned char *blob, unsigned int bloblen, unsigned char *rawdata, unsigned int *datalen) { unsigned char unseal_fmt[] = "00 C3 T l l % l % o % l % o %"; unsigned char unseal_fmt_noauth[] = "00 C2 T l l % l % o %"; uint32_t ret; unsigned char tpmdata[TPM_MAX_BUFF_SIZE]; unsigned char nonceodd[TPM_NONCE_SIZE]; unsigned char enonce1[TPM_NONCE_SIZE]; unsigned char enonce2[TPM_NONCE_SIZE]; unsigned char dummyauth[TPM_NONCE_SIZE]; unsigned char *passptr2; unsigned char c; uint32_t ordinal; uint32_t keyhndl; uint32_t authhandle1; uint32_t authhandle2; unsigned char authdata1[TPM_HASH_SIZE]; unsigned char authdata2[TPM_HASH_SIZE]; memset(dummyauth, 0, sizeof dummyauth); /* check input arguments */ if (rawdata == NULL || blob == NULL) return ERR_NULL_ARG; if (dataauth == NULL) passptr2 = dummyauth; else passptr2 = dataauth; if (keyauth != NULL) { /* key password specified */ /* open TWO OIAP sessions, Key and Data */ ret = TSS_OIAPopen(&authhandle1, enonce1); if (ret != 0) return ret; ret = TSS_OIAPopen(&authhandle2, enonce2); if (ret != 0) return ret; /* data to Network byte order variables for HMAC calculation */ ordinal = htonl(0x18); keyhndl = htonl(keyhandle); /* generate odd nonce */ TSS_gennonce(nonceodd); c = 0; /* calculate KEY authorization HMAC value */ ret = TSS_authhmac(authdata1, keyauth, TPM_HASH_SIZE, enonce1, nonceodd, c, TPM_U32_SIZE, &ordinal, bloblen, blob, 0, 0); if (ret != 0) { TSS_OIAPclose(authhandle1); TSS_OIAPclose(authhandle2); return ret; } /* calculate DATA authorization HMAC value */ ret = TSS_authhmac(authdata2, passptr2, TPM_NONCE_SIZE, enonce2, nonceodd, c, TPM_U32_SIZE, &ordinal, bloblen, blob, 0, 0); if (ret != 0) { TSS_OIAPclose(authhandle1); TSS_OIAPclose(authhandle2); return ret; } /* build the request buffer */ ret = TSS_buildbuff(unseal_fmt, tpmdata, ordinal, keyhndl, bloblen, blob, authhandle1, TPM_NONCE_SIZE, nonceodd, c, TPM_HASH_SIZE, authdata1, authhandle2, TPM_NONCE_SIZE, nonceodd, c, TPM_HASH_SIZE, authdata2); if ((ret & ERR_MASK) != 0) { TSS_OIAPclose(authhandle1); TSS_OIAPclose(authhandle2); return ret; } /* transmit buffer to the TPM device and read the reply */ ret = TPM_Transmit(tpmdata, "Unseal"); if (ret != 0) { TSS_OIAPclose(authhandle1); TSS_OIAPclose(authhandle2); return ret; } *datalen = LOAD32(tpmdata, TPM_DATA_OFFSET); /* check HMAC in response */ ret = TSS_checkhmac2(tpmdata, ordinal, nonceodd, keyauth, TPM_HASH_SIZE, passptr2, TPM_HASH_SIZE, TPM_U32_SIZE, TPM_DATA_OFFSET, *datalen, TPM_DATA_OFFSET + TPM_U32_SIZE, 0, 0); TSS_OIAPclose(authhandle1); TSS_OIAPclose(authhandle2); if (ret != 0) return ret; } else { /* no key password */ /* open ONE OIAP session, for the Data */ ret = TSS_OIAPopen(&authhandle2, enonce2); if (ret != 0) return ret; /* data to Network byte order variables for HMAC calculation */ ordinal = htonl(0x18); keyhndl = htonl(keyhandle); /* generate odd nonce */ TSS_gennonce(nonceodd); c = 0; /* calculate DATA authorization HMAC value */ ret = TSS_authhmac(authdata2, passptr2, TPM_NONCE_SIZE, enonce2, nonceodd, c, TPM_U32_SIZE, &ordinal, bloblen, blob, 0, 0); if (ret != 0) { TSS_OIAPclose(authhandle2); return ret; } /* build the request buffer */ ret = TSS_buildbuff(unseal_fmt_noauth, tpmdata, ordinal, keyhndl, bloblen, blob, authhandle2, TPM_NONCE_SIZE, nonceodd, c, TPM_HASH_SIZE, authdata2); if ((ret & ERR_MASK) != 0) { TSS_OIAPclose(authhandle2); return ret; } /* transmit buffer to the TPM device and read the reply */ ret = TPM_Transmit(tpmdata, "Unseal"); if (ret != 0) { TSS_OIAPclose(authhandle2); return ret; } *datalen = LOAD32(tpmdata, TPM_DATA_OFFSET); /* check HMAC in response */ ret = TSS_checkhmac1(tpmdata, ordinal, nonceodd, passptr2, TPM_HASH_SIZE, TPM_U32_SIZE, TPM_DATA_OFFSET, *datalen, TPM_DATA_OFFSET + TPM_U32_SIZE, 0, 0); TSS_OIAPclose(authhandle2); if (ret != 0) return ret; } /* copy decrypted data back to caller */ memcpy(rawdata, tpmdata + TPM_DATA_OFFSET + TPM_U32_SIZE, *datalen); return 0; }