blob: f43fb178a1feb687ca38d95a1d9ae1d2bfeff6a7 [file] [log] [blame]
/********************************************************************************/
/* */
/* RSA_Decrypt */
/* Written by Ken Goldman */
/* IBM Thomas J. Watson Research Center */
/* */
/* (c) Copyright IBM Corporation 2015 - 2020 */
/* */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or without */
/* modification, are permitted provided that the following conditions are */
/* met: */
/* */
/* Redistributions of source code must retain the above copyright notice, */
/* this list of conditions and the following disclaimer. */
/* */
/* Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in the */
/* documentation and/or other materials provided with the distribution. */
/* */
/* Neither the names of the IBM Corporation nor the names of its */
/* contributors may be used to endorse or promote products derived from */
/* this software without specific prior written permission. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */
/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/********************************************************************************/
/*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <ibmtss/tss.h>
#include <ibmtss/tssutils.h>
#include <ibmtss/tssresponsecode.h>
#include <ibmtss/tssmarshal.h>
#include <ibmtss/tsscryptoh.h>
static void printRsaDecrypt(RSA_Decrypt_Out *out);
static TPM_RC getKeySize(TSS_CONTEXT *tssContext,
TPMI_RSA_KEY_BITS *keyBits,
TPMI_DH_PCR objectHandle);
static TPM_RC padData(uint8_t **buffer,
size_t *padLength,
TPMI_ALG_HASH halg,
TPMI_RSA_KEY_BITS keyBits);
static void printUsage(void);
extern int tssUtilsVerbose;
int main(int argc, char *argv[])
{
TPM_RC rc = 0;
int i; /* argc iterator */
TSS_CONTEXT *tssContext = NULL;
RSA_Decrypt_In in;
RSA_Decrypt_Out out;
TPMI_DH_OBJECT keyHandle = 0;
TPMI_RSA_KEY_BITS keyBits;
const char *encryptFilename = NULL;
const char *decryptFilename = NULL;
const char *keyPassword = NULL;
const char *keyPasswordFilename = NULL;
uint8_t *keyPasswordBuffer = NULL;
size_t keyPasswordBufferLength = 0;
const char *keyPasswordPtr = NULL;
TPMI_ALG_HASH halg = TPM_ALG_NULL;
TPMI_SH_AUTH_SESSION sessionHandle0 = TPM_RS_PW;
unsigned int sessionAttributes0 = 0;
TPMI_SH_AUTH_SESSION sessionHandle1 = TPM_RH_NULL;
unsigned int sessionAttributes1 = 0;
TPMI_SH_AUTH_SESSION sessionHandle2 = TPM_RH_NULL;
unsigned int sessionAttributes2 = 0;
uint16_t written;
size_t length; /* input data */
uint8_t *buffer = NULL; /* for the free */
setvbuf(stdout, 0, _IONBF, 0); /* output may be going through pipe to log file */
TSS_SetProperty(NULL, TPM_TRACE_LEVEL, "1");
tssUtilsVerbose = FALSE;
/* command line argument defaults */
for (i=1 ; (i<argc) && (rc == 0) ; i++) {
if (strcmp(argv[i],"-hk") == 0) {
i++;
if (i < argc) {
sscanf(argv[i],"%x",&keyHandle);
}
else {
printf("Missing parameter for -hk\n");
printUsage();
}
}
else if (strcmp(argv[i],"-pwdk") == 0) {
i++;
if (i < argc) {
keyPassword = argv[i];
}
else {
printf("-pwdk option needs a value\n");
printUsage();
}
}
else if (strcmp(argv[i],"-ipwdk") == 0) {
i++;
if (i < argc) {
keyPasswordFilename = argv[i];
}
else {
printf("-ipwdk option needs a value\n");
printUsage();
}
}
else if (strcmp(argv[i],"-oid") == 0) {
i++;
if (i < argc) {
if (strcmp(argv[i],"sha1") == 0) {
halg = TPM_ALG_SHA1;
}
else if (strcmp(argv[i],"sha256") == 0) {
halg = TPM_ALG_SHA256;
}
else if (strcmp(argv[i],"sha384") == 0) {
halg = TPM_ALG_SHA384;
}
else if (strcmp(argv[i],"sha512") == 0) {
halg = TPM_ALG_SHA512;
}
else {
printf("Bad parameter %s for -oid\n", argv[i]);
printUsage();
}
}
else {
printf("-oid option needs a value\n");
printUsage();
}
}
else if (strcmp(argv[i],"-ie") == 0) {
i++;
if (i < argc) {
encryptFilename = argv[i];
}
else {
printf("-ie option needs a value\n");
printUsage();
}
}
else if (strcmp(argv[i],"-od") == 0) {
i++;
if (i < argc) {
decryptFilename = argv[i];
}
else {
printf("-od option needs a value\n");
printUsage();
}
}
else if (strcmp(argv[i],"-se0") == 0) {
i++;
if (i < argc) {
sscanf(argv[i],"%x", &sessionHandle0);
}
else {
printf("Missing parameter for -se0\n");
printUsage();
}
i++;
if (i < argc) {
sscanf(argv[i],"%x", &sessionAttributes0);
if (sessionAttributes0 > 0xff) {
printf("Out of range session attributes for -se0\n");
printUsage();
}
}
else {
printf("Missing parameter for -se0\n");
printUsage();
}
}
else if (strcmp(argv[i],"-se1") == 0) {
i++;
if (i < argc) {
sscanf(argv[i],"%x", &sessionHandle1);
}
else {
printf("Missing parameter for -se1\n");
printUsage();
}
i++;
if (i < argc) {
sscanf(argv[i],"%x", &sessionAttributes1);
if (sessionAttributes1 > 0xff) {
printf("Out of range session attributes for -se1\n");
printUsage();
}
}
else {
printf("Missing parameter for -se1\n");
printUsage();
}
}
else if (strcmp(argv[i],"-se2") == 0) {
i++;
if (i < argc) {
sscanf(argv[i],"%x", &sessionHandle2);
}
else {
printf("Missing parameter for -se2\n");
printUsage();
}
i++;
if (i < argc) {
sscanf(argv[i],"%x", &sessionAttributes2);
if (sessionAttributes2 > 0xff) {
printf("Out of range session attributes for -se2\n");
printUsage();
}
}
else {
printf("Missing parameter for -se2\n");
printUsage();
}
}
else if (strcmp(argv[i],"-h") == 0) {
printUsage();
}
else if (strcmp(argv[i],"-v") == 0) {
tssUtilsVerbose = TRUE;
TSS_SetProperty(NULL, TPM_TRACE_LEVEL, "2");
}
else {
printf("\n%s is not a valid option\n", argv[i]);
printUsage();
}
}
if (keyHandle == 0) {
printf("Missing handle parameter -hk\n");
printUsage();
}
if (encryptFilename == NULL) {
printf("Missing encrypted message -ie\n");
printUsage();
}
if ((keyPassword != NULL) && (keyPasswordFilename != NULL)) {
printf("Only one of -pwdk and -ipwdk can be specified\n");
printUsage();
}
if (rc == 0) {
/* use passsword from command line */
if (keyPassword != NULL) {
keyPasswordPtr = keyPassword;
}
/* use password from file */
else if (keyPasswordFilename != NULL) {
rc = TSS_File_ReadBinaryFile(&keyPasswordBuffer, /* freed @2 */
&keyPasswordBufferLength,
keyPasswordFilename);
keyPasswordPtr = (const char *)keyPasswordBuffer;
}
/* empty password */
else {
keyPasswordPtr = NULL;
}
}
/* Start a TSS context */
if (rc == 0) {
rc = TSS_Create(&tssContext);
}
/* get the public modulus size for checks and padding */
if (rc == 0) {
rc = getKeySize(tssContext, &keyBits, keyHandle);
}
if (rc == 0) {
rc = TSS_File_ReadBinaryFile(&buffer, /* freed @1 */
&length,
encryptFilename);
}
if (rc == 0) {
if (length > (keyBits / 8U)) {
printf("Input data too long %u\n", (unsigned int)length);
rc = TSS_RC_INSUFFICIENT_BUFFER;
}
}
/* if an OID was requested, treat the encryptFilename as a hash to be signed */
if ((rc == 0) && (halg != TPM_ALG_NULL)) {
rc = padData(&buffer, /* realloced to fit */
&length, /* resized for OID and pad */
halg, /* gigest algorithm for size and OID */
keyBits); /* RSA modulus length in bits */
}
if (rc == 0) {
/* Handle of key that will perform rsa decrypt */
in.keyHandle = keyHandle;
/* Table 158 - Definition of {RSA} TPM2B_PUBLIC_KEY_RSA Structure */
{
in.cipherText.t.size = (uint16_t)length; /* cast safe, range tested above */
memcpy(in.cipherText.t.buffer, buffer, length);
}
/* padding scheme */
{
/* Table 157 - Definition of {RSA} TPMT_RSA_DECRYPT Structure */
in.inScheme.scheme = TPM_ALG_NULL;
}
/* label */
{
/* Table 73 - Definition of TPM2B_DATA Structure */
in.label.t.size = 0;
}
}
free(buffer); /* @1 */
buffer = NULL;
/* call TSS to execute the command */
if (rc == 0) {
rc = TSS_Execute(tssContext,
(RESPONSE_PARAMETERS *)&out,
(COMMAND_PARAMETERS *)&in,
NULL,
TPM_CC_RSA_Decrypt,
sessionHandle0, keyPasswordPtr, sessionAttributes0,
sessionHandle1, NULL, sessionAttributes1,
sessionHandle2, NULL, sessionAttributes2,
TPM_RH_NULL, NULL, 0);
}
{
TPM_RC rc1 = TSS_Delete(tssContext);
if (rc == 0) {
rc = rc1;
}
}
if ((rc == 0) && (decryptFilename != NULL)) {
rc = TSS_Structure_Marshal(&buffer, /* freed @1 */
&written,
&out.message,
(MarshalFunction_t)TSS_TPM2B_PUBLIC_KEY_RSA_Marshalu);
}
if ((rc == 0) && (decryptFilename != NULL)) {
rc = TSS_File_WriteBinaryFile(buffer + sizeof(uint16_t),
written - sizeof(uint16_t),
decryptFilename);
}
if (rc == 0) {
if (tssUtilsVerbose) printRsaDecrypt(&out);
if (tssUtilsVerbose) printf("rsadecrypt: success\n");
}
else {
const char *msg;
const char *submsg;
const char *num;
printf("rsadecrypt: failed, rc %08x\n", rc);
TSS_ResponseCode_toString(&msg, &submsg, &num, rc);
printf("%s%s%s\n", msg, submsg, num);
rc = EXIT_FAILURE;
}
free(buffer); /* @1 */
free(keyPasswordBuffer); /* @2 */
return rc;
}
/* padData() is used then the private key operation is a signing operation over a hash. It takes a
'buffer' of original 'length'. The original length should match the hash algorithm digest size.
buffer is realloc'ed to the key size, than then padded with the OID for the hash algorithm and
the PKCS1 padding.
*/
static TPM_RC padData(uint8_t **buffer,
size_t *padLength,
TPMI_ALG_HASH halg,
TPMI_RSA_KEY_BITS keyBits)
{
TPM_RC rc = 0;
uint16_t digestSize;
const uint8_t *oid;
uint16_t oidSize;
const uint8_t sha1Oid[] = {SHA1_DER};
const uint8_t sha256Oid[] = {SHA256_DER};
const uint8_t sha384Oid[] = {SHA384_DER};
const uint8_t sha512Oid[] = {SHA512_DER};
/* check that the original buffer length matches the hash algorithm */
if (rc == 0) {
digestSize = TSS_GetDigestSize(halg);
if (digestSize == 0) {
printf("padData: Unsupported hash algorithm %04x\n", halg);
rc = TPM_RC_HASH;
}
}
if (rc == 0) {
if (digestSize != *padLength) {
unsigned long pl = *padLength;
printf("paddata: hash algorithm length %u not equal data length %lu\n",
digestSize, pl);
rc = TPM_RC_VALUE;
}
}
/* realloc the buffer to the key size in bytes */
if (rc == 0) {
*padLength = keyBits / 8;
rc = TSS_Realloc(buffer, *padLength);
}
/* determine the OID */
if (rc == 0) {
switch (halg) {
case TPM_ALG_SHA1:
oid = sha1Oid;
oidSize = SHA1_DER_SIZE;
break;
case TPM_ALG_SHA256:
oid = sha256Oid;
oidSize = SHA256_DER_SIZE;
break;
case TPM_ALG_SHA384:
oid = sha384Oid;
oidSize = SHA384_DER_SIZE;
break;
case TPM_ALG_SHA512:
oid = sha512Oid;
oidSize = SHA512_DER_SIZE;
break;
default:
printf("padData: Unsupported hash algorithm %04x\n", halg);
rc = TPM_RC_HASH;
}
}
if (rc == 0) {
/* move the hash to the end */
memmove(*buffer + *padLength - digestSize, *buffer, digestSize);
/* prepend the OID */
memcpy(*buffer + *padLength - digestSize - oidSize, oid, oidSize);
/* prepend the PKCS1 pad */
(*buffer)[0] = 0x00;
(*buffer)[1] = 0x01;
memset(&(*buffer)[2], 0xff, *padLength - 3 - oidSize - digestSize);
(*buffer)[*padLength - oidSize - digestSize - 1] = 0x00;
if (tssUtilsVerbose) TSS_PrintAll("padData: padded data", *buffer, *padLength);
}
return rc;
}
/* getKeySize() gets the key size in bits */
static TPM_RC getKeySize(TSS_CONTEXT *tssContext,
TPMI_RSA_KEY_BITS *keyBits,
TPMI_DH_PCR objectHandle)
{
TPM_RC rc = 0;
ReadPublic_In in;
ReadPublic_Out out;
/* call TSS to execute the command */
if (rc == 0) {
in.objectHandle = objectHandle;
rc = TSS_Execute(tssContext,
(RESPONSE_PARAMETERS *)&out,
(COMMAND_PARAMETERS *)&in,
NULL,
TPM_CC_ReadPublic,
TPM_RH_NULL, NULL, 0);
}
if (rc == 0) {
*keyBits = out.outPublic.publicArea.parameters.rsaDetail.keyBits;
if (tssUtilsVerbose) printf("getKeySize: size %u\n", *keyBits);
}
return rc;
}
static void printRsaDecrypt(RSA_Decrypt_Out *out)
{
TSS_PrintAll("outData", out->message.t.buffer, out->message.t.size);
}
static void printUsage(void)
{
printf("\n");
printf("rsadecrypt\n");
printf("\n");
printf("Runs TPM2_RSA_Decrypt\n");
printf("\n");
printf("\t-hk\tkey handle\n");
printf("\t[-pwdk\tpassword for key (default empty)[\n");
printf("\t[-ipwdk\tpassword file for key, nul terminated (default empty)]\n");
printf("\t-ie\tencrypt file name\n");
printf("\t-od\tdecrypt file name (default do not save)\n");
printf("\t[-oid\t(sha1, sha256, sha384 sha512)]\n");
printf("\t\toptionally add OID and PKCS1 padding to the\n");
printf("\t\tencrypt data (demo of signing with arbitrary OID)\n");
printf("\n");
printf("\t-se[0-2] session handle / attributes (default PWAP)\n");
printf("\t01\tcontinue\n");
printf("\t20\tcommand decrypt\n");
printf("\t40\tresponse encrypt\n");
exit(1);
}