blob: ace43d0c4a7e3eb434e12248f188a443753848b8 [file] [log] [blame]
/********************************************************************************/
/* */
/* CertifyX509 */
/* Written by Ken Goldman */
/* IBM Thomas J. Watson Research Center */
/* */
/* (c) Copyright IBM Corporation 2019. */
/* */
/* 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. */
/********************************************************************************/
/* CertifyX509 exercises the TPM2_CertifyX509 command. It:
- Creates a partialCertificate parameter
- Runs the TPM2_CertifyX509 command
- Reconstructs the X509 certificate from the addedToCertificate and signature outputs
*/
/* mbedtls does not support this utility */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "cryptoutils.h"
#ifndef TPM_TSS_MBEDTLS
#include <ibmtss/tss.h>
#include <ibmtss/tssutils.h>
#include <ibmtss/tssresponsecode.h>
#include <ibmtss/tssmarshal.h>
#include <ibmtss/Unmarshal_fp.h>
#include <ibmtss/tssfile.h>
/* NOTE: This is currently openssl only. */
#include <ekutils.h>
static void printUsage(void);
TPM_RC createPartialCertificate(X509 *x509Certificate,
uint8_t *partialCertificateDer,
uint16_t *partialCertificateDerLength,
size_t partialCertificateDerSize,
const char *keyUsage,
uint32_t tpmaObject,
int addTpmaObject,
int subeqiss);
TPM_RC convertCertToPartialCert(uint16_t *partialCertificateDerLength,
uint8_t *partialCertificateDer,
uint16_t certificateDerLength,
uint8_t *certificateDer);
TPM_RC reformCertificate(X509 *x509Certificate,
int useRsa,
TPM2B_MAX_BUFFER *addedToCertificate,
TPMT_SIGNATURE *tSignature);
TPM_RC addSerialNumber(X509 *x509Certificate,
unsigned char *tmpAddedToCert,
uint16_t *tmpAddedToCertIndex);
TPM_RC addPubKeyRsa(X509 *x509Certificate,
unsigned char *tmpAddedToCert,
uint16_t *tmpAddedToCertIndex);
TPM_RC addSignatureRsa(X509 *x509Certificate,
TPMT_SIGNATURE *tSignature);
TPM_RC addSignatureEcc(X509 *x509Certificate,
TPMT_SIGNATURE *signature);
TPM_RC addPubKeyEcc(X509 *x509Certificate,
unsigned char *tmpAddedToCert,
uint16_t *tmpAddedToCertIndex);
TPM_RC addCertExtensionTpmaOid(X509 *x509Certificate,
uint32_t tpmaObject);
TPM_RC getDataLength(uint8_t type,
uint16_t *wrapperLength,
uint16_t *dataLength,
uint16_t *certificateDerIndex,
uint8_t *certificateDer);
TPM_RC skipSequence(uint16_t *certificateDerIndex, uint8_t *certificateDer);
TPM_RC skipBitString(uint16_t *dataLength,
uint16_t *certificateDerIndex, uint8_t *certificateDer);
TPM_RC copyType(uint8_t type,
uint16_t *partialCertificateDerLength, uint8_t *partialCertificateDer,
uint16_t *certificateDerIndex, uint8_t *certificateDer);
TPM_RC getInteger(uint16_t *integerLength, unsigned char *integerStream,
uint16_t *certificateDerIndex, unsigned char *certificateDer);
TPM_RC prependSequence(uint16_t *partialCertificateDerLength, uint8_t *partialCertificateDer);
int verbose = FALSE;
/* FIXME
length checks
*/
int main(int argc, char *argv[])
{
TPM_RC rc = 0;
int i; /* argc iterator */
TSS_CONTEXT *tssContext = NULL;
CertifyX509_In in;
CertifyX509_Out out;
TPMI_DH_OBJECT objectHandle = 0;
TPMI_DH_OBJECT signHandle = 0;
TPMI_ALG_HASH halg = TPM_ALG_SHA256;
unsigned int bit = 0;
int testBit = FALSE;
const char *keyPassword = NULL;
const char *objectPassword = NULL;
const char *outPartialCertificateFilename = NULL;
const char *outCertificateFilename = NULL;
const char *addedToCertificateFilename = NULL;
const char *tbsDigestFilename = NULL;
const char *signatureFilename = NULL;
TPMI_SH_AUTH_SESSION sessionHandle0 = TPM_RS_PW;
unsigned int sessionAttributes0 = 0;
TPMI_SH_AUTH_SESSION sessionHandle1 = TPM_RS_PW;
unsigned int sessionAttributes1 = 0;
TPMI_SH_AUTH_SESSION sessionHandle2 = TPM_RH_NULL;
unsigned int sessionAttributes2 = 0;
int useRsa = 1;
int subeqiss = FALSE; /* TRUE: subject = issuer */
const char *keyUsage = "critical,digitalSignature,keyCertSign,cRLSign";
uint32_t tpmaObject = 0;
int addTpmaObject = FALSE;
X509 *x509Certificate = NULL;
unsigned char *x509Der = NULL;
uint32_t x509DerLength = 0;
setvbuf(stdout, 0, _IONBF, 0); /* output may be going through pipe to log file */
TSS_SetProperty(NULL, TPM_TRACE_LEVEL, "1");
/* command line argument defaults */
for (i=1 ; (i<argc) && (rc == 0) ; i++) {
if (strcmp(argv[i],"-ho") == 0) {
i++;
if (i < argc) {
sscanf(argv[i],"%x",&objectHandle);
}
else {
printf("Missing parameter for -ho\n");
printUsage();
}
}
else if (strcmp(argv[i],"-pwdo") == 0) {
i++;
if (i < argc) {
objectPassword = argv[i];
}
else {
printf("-pwdo option needs a value\n");
printUsage();
}
}
else if (strcmp(argv[i],"-hk") == 0) {
i++;
if (i < argc) {
sscanf(argv[i],"%x",&signHandle);
}
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],"-halg") == 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 -halg\n", argv[i]);
printUsage();
}
}
else {
printf("-halg option needs a value\n");
printUsage();
}
}
else if (strcmp(argv[i],"-salg") == 0) {
i++;
if (i < argc) {
if (strcmp(argv[i],"rsa") == 0) {
useRsa = 1;
}
else if (strcmp(argv[i],"ecc") == 0) {
useRsa = 0;
}
else {
printf("Bad parameter %s for -salg\n", argv[i]);
printUsage();
}
}
else {
printf("-salg option needs a value\n");
printUsage();
}
}
else if (strcmp(argv[i],"-ku") == 0) {
i++;
if (i < argc) {
keyUsage = argv[i];
}
else {
printf("-ku option needs a value\n");
printUsage();
}
}
else if (strcmp(argv[i],"-iob") == 0) {
i++;
if (i < argc) {
addTpmaObject = TRUE;
sscanf(argv[i], "%x", &tpmaObject);
}
else {
printf("-iob option needs a value\n");
printUsage();
}
}
else if (strcmp(argv[i],"-sub") == 0) {
subeqiss = TRUE;
}
else if (strcmp(argv[i],"-opc") == 0) {
i++;
if (i < argc) {
outPartialCertificateFilename = argv[i];
}
else {
printf("-opc option needs a value\n");
printUsage();
}
}
else if (strcmp(argv[i],"-ocert") == 0) {
i++;
if (i < argc) {
outCertificateFilename = argv[i];
}
else {
printf("-ocert option needs a value\n");
printUsage();
}
}
else if (strcmp(argv[i],"-oa") == 0) {
i++;
if (i < argc) {
addedToCertificateFilename = argv[i];
}
else {
printf("-oa option needs a value\n");
printUsage();
}
}
else if (strcmp(argv[i],"-otbs") == 0) {
i++;
if (i < argc) {
tbsDigestFilename = argv[i];
}
else {
printf("-otbs option needs a value\n");
printUsage();
}
}
else if (strcmp(argv[i],"-os") == 0) {
i++;
if (i < argc) {
signatureFilename = argv[i];
}
else {
printf("-os 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) {
verbose = TRUE;
TSS_SetProperty(NULL, TPM_TRACE_LEVEL, "2");
}
else {
printf("\n%s is not a valid option\n", argv[i]);
printUsage();
}
}
if (objectHandle == 0) {
printf("Missing object handle parameter -ho\n");
printUsage();
}
if (signHandle == 0) {
printf("Missing sign handle parameter -hk\n");
printUsage();
}
if (rc == 0) {
/* Handle of the object to be certified */
in.objectHandle = objectHandle;
/* Handle of key that will perform certifying */
in.signHandle = signHandle;
if (useRsa) {
/* Table 145 - Definition of TPMT_SIG_SCHEME Structure */
in.inScheme.scheme = TPM_ALG_RSASSA;
/* Table 144 - Definition of TPMU_SIG_SCHEME Union <IN/OUT, S> */
/* Table 142 - Definition of {RSA} Types for RSA Signature Schemes */
/* Table 135 - Definition of TPMS_SCHEME_HASH Structure */
in.inScheme.details.rsassa.hashAlg = halg;
}
else { /* ecc */
in.inScheme.scheme = TPM_ALG_ECDSA;
in.inScheme.details.ecdsa.hashAlg = halg;
}
in.reserved.t.size = 0;
}
/* initialize a new, empty X509 structure. It will first be used to form the partialCertificate
command parameter, and then be used to reform the certificate from the response
parameters. */
if (rc == 0) {
x509Certificate = X509_new(); /* freed @1 */
if (x509Certificate == NULL) {
printf("main: Error in X509_new\n");
rc = TSS_RC_OUT_OF_MEMORY;
}
}
/* form partial certificate */
if (rc == 0) {
rc = createPartialCertificate(x509Certificate,
in.partialCertificate.t.buffer,
&in.partialCertificate.b.size,
sizeof(in.partialCertificate.t.buffer),
keyUsage,
tpmaObject,
addTpmaObject,
subeqiss);
}
if ((rc == 0) && (testBit)) {
unsigned int bitInByte = bit % 8;
unsigned int byteInDer = bit / 8;
if (byteInDer <= in.partialCertificate.b.size) {
if (verbose) {
printf("main: Testing byte %u bit %u\n", byteInDer, bitInByte);
printf("main: Byte was %02x\n", in.partialCertificate.t.buffer[byteInDer]);
}
in.partialCertificate.t.buffer[byteInDer] ^= (1 << bitInByte);
if (verbose) printf("main: Byte is %02x\n", in.partialCertificate.t.buffer[byteInDer]);
}
else {
printf("Bad -bit parameter, byte %u, DER length %u\n",
byteInDer, in.partialCertificate.b.size);
rc = TSS_RC_BAD_PROPERTY;
}
}
/* for debug, or stop here for sample of how to create the partialCertificate parameter */
if (rc == 0) {
if (outPartialCertificateFilename != NULL) {
rc = TSS_File_WriteBinaryFile(in.partialCertificate.b.buffer,
in.partialCertificate.b.size,
outPartialCertificateFilename);
}
}
/* Start a TSS context */
if (rc == 0) {
rc = TSS_Create(&tssContext);
}
/* call TSS to execute the command */
if (rc == 0) {
rc = TSS_Execute(tssContext,
(RESPONSE_PARAMETERS *)&out,
(COMMAND_PARAMETERS *)&in,
NULL,
TPM_CC_CertifyX509,
sessionHandle0, objectPassword, sessionAttributes0,
sessionHandle1, keyPassword, sessionAttributes1,
sessionHandle2, NULL, sessionAttributes2,
TPM_RH_NULL, NULL, 0);
}
{
TPM_RC rc1 = TSS_Delete(tssContext);
if (rc == 0) {
rc = rc1;
}
}
if (rc != 0) {
const char *msg;
const char *submsg;
const char *num;
printf("certifyx509: failed, rc %08x\n", rc);
TSS_ResponseCode_toString(&msg, &submsg, &num, rc);
printf("%s%s%s\n", msg, submsg, num);
rc = EXIT_FAILURE;
}
/* write response parameters for debug */
if ((rc == 0) && (addedToCertificateFilename != NULL)) {
rc = TSS_File_WriteBinaryFile(out.addedToCertificate.t.buffer,
out.addedToCertificate.t.size,
addedToCertificateFilename);
}
if ((rc == 0) && (tbsDigestFilename != NULL)) {
rc = TSS_File_WriteBinaryFile(out.tbsDigest.t.buffer,
out.tbsDigest.t.size,
tbsDigestFilename);
}
if ((rc == 0) && (signatureFilename != NULL)) {
rc = TSS_File_WriteStructure(&out.signature,
(MarshalFunction_t)TSS_TPMT_SIGNATURE_Marshalu,
signatureFilename);
}
if (rc == 0) {
if (verbose) TSS_TPMT_SIGNATURE_Print(&out.signature, 0);
}
/* reform the signed certificate from the original input plus the response parameters */
if (rc == 0) {
rc = reformCertificate(x509Certificate,
useRsa,
&out.addedToCertificate,
&out.signature);
}
if (rc == 0) {
if (verbose) X509_print_fp(stdout, x509Certificate); /* for debug */
rc = convertX509ToDer(&x509DerLength,
&x509Der, /* freed @2 */
x509Certificate);
}
if ((rc == 0) && (outCertificateFilename != NULL)) {
rc = TSS_File_WriteBinaryFile(x509Der, x509DerLength,
outCertificateFilename);
}
if (x509Certificate != NULL) {
X509_free(x509Certificate); /* @1 */
}
free(x509Der); /* @2 */
return rc;
}
/* example of a 20 year validity */
#define CERT_DURATION (60 * 60 * 24 * ((365 * 20) + 5)) /* +5 for leap years */
/* in this test, the issuer and subject are the same, making a self signed certificate. This is
simply so that openssl can be used to verify the certificate signature.
*/
char *issuerEntries[] = {
"US" ,
"NY" ,
"Yorktown" ,
"IBM" ,
NULL ,
"CA" ,
NULL
};
char *subjectEntries[] = {
"US" ,
"NY" ,
"Yorktown" ,
"IBM" ,
NULL ,
"Subject" ,
NULL
};
/* createPartialCertificate() forms the partialCertificate DER. It starts with an empty X509
structure and adds the needed parameters. Then (in a total hack), converts the X509 structure to
DER, parses the DER field by field, and outputs just the fields required for the
partialCertificate parameter.
subeqiss FALSE: subject name is independent of issuer name
subeqiss TRUE: subject name is the same as the issuer name
*/
TPM_RC createPartialCertificate(X509 *x509Certificate, /* input / output */
uint8_t *partialCertificateDer, /* output */
uint16_t *partialCertificateDerLength,
size_t partialCertificateDerSize,
const char *keyUsage,
uint32_t tpmaObject,
int addTpmaObject,
int subeqiss) /* subject variation */
{
TPM_RC rc = 0;
int irc;
ASN1_TIME *arc; /* return code */
X509_NAME *x509IssuerName = NULL; /* composite issuer name, key/value pairs */
X509_NAME *x509SubjectName = NULL;/* composite subject name, key/value pairs */
size_t issuerEntriesSize = sizeof(issuerEntries)/sizeof(char *);
size_t subjectEntriesSize = sizeof(subjectEntries)/sizeof(char *);
uint32_t certificateDerLength = 0;
uint8_t *certificateDer = NULL;
partialCertificateDerSize = partialCertificateDerSize; /* FIXME needs size check */
/* add certificate version X509 v3 */
if (rc == 0) {
irc = X509_set_version(x509Certificate, 2L); /* value 2 == v3 */
if (irc != 1) {
printf("createPartialCertificate: Error in X509_set_version\n");
rc = TSS_RC_X509_ERROR;
}
}
/* add issuer */
if (rc == 0) {
if (verbose) printf("createPartialCertificate: Adding issuer, size %lu\n",
(unsigned long)issuerEntriesSize);
rc = createX509Name(&x509IssuerName,
issuerEntriesSize,
issuerEntries);
}
if (rc == 0) {
irc = X509_set_issuer_name(x509Certificate, x509IssuerName);
if (irc != 1) {
printf("createPartialCertificate: Error setting issuer\n");
rc = TSS_RC_X509_ERROR;
}
}
/* add validity */
if (rc == 0) {
/* can't fail, just returns a structure member */
ASN1_TIME *notBefore = X509_get_notBefore(x509Certificate);
arc = X509_gmtime_adj(notBefore ,0L); /* set to today */
if (arc == NULL) {
printf("createPartialCertificate: Error setting notBefore time\n");
rc = TSS_RC_X509_ERROR;
}
}
if (rc == 0) {
/* can't fail, just returns a structure member */
ASN1_TIME *notAfter = X509_get_notAfter(x509Certificate);
arc = X509_gmtime_adj(notAfter, CERT_DURATION); /* set to duration */
if (arc == NULL) {
printf("createPartialCertificate: Error setting notAfter time\n");
rc = TSS_RC_X509_ERROR;
}
}
/* add subject */
if (rc == 0) {
/* normal case */
if (!subeqiss) {
if (verbose) printf("createPartialCertificate: Adding subject, size %lu\n",
(unsigned long)subjectEntriesSize);
rc = createX509Name(&x509SubjectName,
subjectEntriesSize,
subjectEntries);
}
/* special case, self signed CA, make the subject the same as the issuer */
else {
if (verbose) printf("createPartialCertificate: Adding subject (issuer), size %lu\n",
(unsigned long)issuerEntriesSize);
rc = createX509Name(&x509SubjectName,
issuerEntriesSize,
issuerEntries);
}
}
if (rc == 0) {
irc = X509_set_subject_name(x509Certificate, x509SubjectName);
if (irc != 1) {
printf("createPartialCertificate: Error setting subject\n");
rc = TSS_RC_X509_ERROR;
}
}
/* add some certificate extensions, requires corresponding bits in subject key */
if (rc == 0) {
if (verbose) printf("createPartialCertificate: Adding extensions\n");
rc = addCertExtension(x509Certificate,
NID_key_usage, keyUsage);
}
/* optional TPMA_OBJECT extension */
/* From TCG OID registry tcg-tpmaObject 2.23.133.10.1.1.1 */
if (rc == 0) {
if (addTpmaObject) {
rc = addCertExtensionTpmaOid(x509Certificate, tpmaObject);
}
}
/* convertX509ToDer() serializes the openSSL X509 structure to a DER certificate stream */
if (rc == 0) {
rc = convertX509ToDer(&certificateDerLength,
&certificateDer, /* freed @4 */
x509Certificate); /* input */
}
/* for debug. The structure is incomplete and so will trace with errors */
if (rc == 0) {
if (verbose) printf("createPartialCertificate: Trace preliminary certificate\n");
if (verbose) X509_print_fp(stdout, x509Certificate);
}
#if 1
/* for debug. Use dumpasn1 to view the incomplete certificate */
if (rc == 0) {
rc = TSS_File_WriteBinaryFile(certificateDer, certificateDerLength , "tmpx509i.bin");
}
#endif
/* extract the partialCertificate DER from the X509 DER */
if (rc == 0) {
rc = convertCertToPartialCert(partialCertificateDerLength,
partialCertificateDer, /* output partial */
certificateDerLength,
certificateDer); /* input X509 */
}
free(certificateDer); /* @4 */
return rc;
}
/* addCertExtension() adds the tpmaObject extension oid to the X509 certificate
*/
TPM_RC addCertExtensionTpmaOid(X509 *x509Certificate, uint32_t tpmaObject)
{
TPM_RC rc = 0;
X509_EXTENSION *extension = NULL; /* freed @1 */
uint8_t tpmaObjectOid[] = {0x06, 0x07, 0x67, 0x81, 0x05, 0x0A, 0x01, 0x01, 0x01};
const uint8_t *tmpOidPtr;
/* BIT STRING 0x03 length 5 no padding 0, 4 dummy bytes of TPMA_OBJECT */
uint8_t tpmaObjectData[] = {0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00};
ASN1_OBJECT *object = NULL;
ASN1_OCTET_STRING *osData = NULL;
uint8_t *tmpOdPtr;
uint32_t tpmaObjectNbo = htonl(tpmaObject);
if (rc == 0) {
tmpOidPtr = tpmaObjectOid;
object = d2i_ASN1_OBJECT(NULL, &tmpOidPtr, sizeof(tpmaObjectOid)); /* freed @2 */
if (object == NULL) {
printf("d2i_ASN1_OBJECT failed\n");
rc = TSS_RC_X509_ERROR;
}
}
if (rc == 0) {
osData = ASN1_OCTET_STRING_new(); /* freed @3 */
if (osData == NULL) {
printf("d2i_ASN1_OCTET_STRING failed\n");
rc = TSS_RC_X509_ERROR;
}
}
if (rc == 0) {
tmpOdPtr = tpmaObjectData;
memcpy(tmpOdPtr + 3, &tpmaObjectNbo, sizeof(uint32_t));
ASN1_OCTET_STRING_set(osData, tmpOdPtr, sizeof (tpmaObjectData));
}
if (rc == 0) {
extension = X509_EXTENSION_create_by_OBJ(NULL, /* freed @1 */
object,
0, /* int crit */
osData);
if (extension == NULL) {
printf("X509_EXTENSION_create_by_OBJ failed\n");
rc = TSS_RC_X509_ERROR;
}
}
if (rc == 0) {
int irc = X509_add_ext(x509Certificate, /* the certificate */
extension, /* the extension to add */
-1); /* location - append */
if (irc != 1) {
printf("addCertExtension: Error adding oid to extension\n");
}
}
if (extension != NULL) {
X509_EXTENSION_free(extension); /* @1 */
}
if (object != NULL) {
ASN1_OBJECT_free(object); /* @2 */
}
if (osData != NULL) {
ASN1_OCTET_STRING_free(osData); /* @3 */
}
return rc;
}
/* convertCertToPartialCert() extracts the partialCertificate DER from the X509 DER
It assumes that the input is well formed and has exactly the fields required.
*/
TPM_RC convertCertToPartialCert(uint16_t *partialCertificateDerLength,
uint8_t *partialCertificateDer,
uint16_t certificateDerLength,
uint8_t *certificateDer)
{
TPM_RC rc = 0;
uint16_t certificateDerIndex = 0; /* index into the DER input */
certificateDerLength = certificateDerLength; /* FIXME for future error checking */
*partialCertificateDerLength = 0; /* updates on each call */
/* skip the outer SEQUENCE wrapper */
if (rc == 0) {
if (verbose) printf("convertCertToPartialCert: Skip outer SEQUENCE wrapper\n");
rc = skipSequence(&certificateDerIndex, certificateDer);
}
/* skip the inner SEQUENCE wrapper, will be back filled with the total length */
if (rc == 0) {
if (verbose) printf("convertCertToPartialCert: Skip inner SEQUENCE wrapper\n");
rc = skipSequence(&certificateDerIndex, certificateDer);
}
/* skip the a3 wrapping the version */
if (rc == 0) {
if (verbose) printf("convertCertToPartialCert: Skip a3 version wrapper\n");
rc = copyType(0xa0, NULL, NULL, /* NULL says to skip */
&certificateDerIndex, certificateDer);
}
/* skip the integer (version) */
if (rc == 0) {
if (verbose) printf("convertCertToPartialCert: Skip version\n");
rc = copyType(0x02, NULL, NULL, /* NULL says to skip */
&certificateDerIndex, certificateDer);
}
/* skip the sequence (serial number) */
if (rc == 0) {
if (verbose) printf("convertCertToPartialCert: Skip serial number\n");
rc = copyType(0x30, NULL, NULL, /* NULL says to skip */
&certificateDerIndex, certificateDer);
}
/* copy the next SEQUENCE, issuer */
if (rc == 0) {
if (verbose) printf("convertCertToPartialCert: Copy issuer\n");
rc = copyType(0x30, partialCertificateDerLength, partialCertificateDer,
&certificateDerIndex, certificateDer);
}
/* copy the next SEQUENCE, validity */
if (rc == 0) {
if (verbose) printf("convertCertToPartialCert: Copy validity\n");
rc = copyType(0x30, partialCertificateDerLength, partialCertificateDer,
&certificateDerIndex, certificateDer);
}
/* copy the next SEQUENCE, subject */
if (rc == 0) {
if (verbose) printf("convertCertToPartialCert: Copy subject\n");
rc = copyType(0x30, partialCertificateDerLength, partialCertificateDer,
&certificateDerIndex, certificateDer);
}
/* skip the SEQUENCE (public key) */
if (rc == 0) {
if (verbose) printf("convertCertToPartialCert: Skip public key\n");
rc = copyType(0x30, NULL, NULL, /* NULL says to skip */
&certificateDerIndex, certificateDer);
}
/* copy the a3 and encapsulating sequence */
if (rc == 0) {
if (verbose) printf("convertCertToPartialCert: Copy a3 extensions\n");
rc = copyType(0xa3, partialCertificateDerLength, partialCertificateDer,
&certificateDerIndex, certificateDer);
}
/* shift and back fill the sequence length */
if (rc == 0) {
rc = prependSequence(partialCertificateDerLength, partialCertificateDer);
}
return rc;
}
/* reformCertificate() starts with the X509 certificate used as the input partialCertificate
parameter plus a few fields like the version. It adds the output addedToCertificate and
signature values to reform the X509 certificate that the TPM signed.
*/
TPM_RC reformCertificate(X509 *x509Certificate,
int useRsa,
TPM2B_MAX_BUFFER *addedToCertificate,
TPMT_SIGNATURE *tSignature)
{
TPM_RC rc = 0;
unsigned char *tmpAddedToCert = NULL;
/* size_t tmpAddedToCertLength = 0; FIXME better to sanity check length */
/* the index increments, so this function must parse the addedToCertificate in its order */
uint16_t tmpAddedToCertIndex = 0;
tmpAddedToCert = addedToCertificate->t.buffer;
/* tmpAddedToCertLength = addedToCertificate->t.size; */
/* add serial number */
if (rc == 0) {
rc = addSerialNumber(x509Certificate,
tmpAddedToCert,
&tmpAddedToCertIndex);
}
if (useRsa) {
/* add public key algorithm and public key */
if (rc == 0) {
rc = addPubKeyRsa(x509Certificate,
tmpAddedToCert,
&tmpAddedToCertIndex);
}
/* add certificate signature */
if (rc == 0) {
rc = addSignatureRsa(x509Certificate, tSignature);
}
}
else {
/* add public key */
if (rc == 0) {
rc = addPubKeyEcc(x509Certificate,
tmpAddedToCert,
&tmpAddedToCertIndex);
}
/* add certificate signature */
if (rc == 0) {
rc = addSignatureEcc(x509Certificate, tSignature);
}
}
return rc;
}
/* addSerialNumber() is the first call from reforming the certificate. tmpAddedToCertIndex will be
0.
After the call, tmpAddedToCertIndex will point after the serial number.
*/
TPM_RC addSerialNumber(X509 *x509Certificate,
unsigned char *tmpAddedToCert,
uint16_t *tmpAddedToCertIndex)
{
TPM_RC rc = 0;
ASN1_INTEGER *x509Serial; /* certificate serial number in ASN1 */
BIGNUM *x509SerialBN; /* certificate serial number as a BIGNUM */
unsigned char x509SerialBin[1048]; /* certificate serial number in binary */
uint16_t integerLength = 0;
/* FIXME check the size */
x509SerialBN = NULL;
/* skip outer sequence */
if (rc == 0) {
rc = skipSequence(tmpAddedToCertIndex, tmpAddedToCert);
}
/* skip version */
if (rc == 0) {
rc = copyType(0xa0, NULL, NULL, /* NULL says to skip */
tmpAddedToCertIndex, tmpAddedToCert);
}
/* get integer serial number from addedToCertificate */
if (rc == 0) {
rc = getInteger(&integerLength, x509SerialBin,
tmpAddedToCertIndex, tmpAddedToCert);
}
/* convert the integer stream to a BIGNUM */
if (rc == 0) {
x509SerialBN = BN_bin2bn(x509SerialBin, integerLength, x509SerialBN); /* freed @1 */
if (x509SerialBN == NULL) {
printf("addSerialNumber: Error in serial number BN_bin2bn\n");
rc = TSS_RC_X509_ERROR;
}
}
/* add it into the final certificate */
if (rc == 0) {
/* get the serial number structure member, can't fail */
x509Serial = X509_get_serialNumber(x509Certificate);
/* convert the BIGNUM to ASN1 and add to X509 certificate */
x509Serial = BN_to_ASN1_INTEGER(x509SerialBN, x509Serial);
if (x509Serial == NULL) {
printf("addSerialNumber: Error setting certificate serial number\n");
rc = TSS_RC_X509_ERROR;
}
}
if (x509SerialBN != NULL) BN_clear_free(x509SerialBN ); /* @1 */
return rc;
}
/* addPubKeyRsa() adds the public key to the certificate. tmpAddedToCertIndex must point to the
public key.
*/
TPM_RC addPubKeyRsa(X509 *x509Certificate,
unsigned char *tmpAddedToCert,
uint16_t *tmpAddedToCertIndex)
{
TPM_RC rc = 0;
TPM2B_PUBLIC_KEY_RSA tpm2bRsa;
uint16_t dataLength;
/* skip the SEQUENCE with the Signature Algorithm object identifier */
if (rc == 0) {
rc = copyType(0x30, NULL, NULL, /* NULL says to skip */
tmpAddedToCertIndex, tmpAddedToCert);
}
/* skip the SEQUENCE wrapper for the Subject Public Key Info */
if (rc == 0) {
rc = skipSequence(tmpAddedToCertIndex, tmpAddedToCert);
}
/* skip the SEQUENCE Public Key Algorithm */
if (rc == 0) {
rc = copyType(0x30, NULL, NULL, /* NULL says to skip */
tmpAddedToCertIndex, tmpAddedToCert);
}
/* skip the BIT STRING intoduction to the public key */
if (rc == 0) {
rc = skipBitString(&dataLength, tmpAddedToCertIndex, tmpAddedToCert);
}
/* skip the SEQUENCE wrapper for the public key */
if (rc == 0) {
rc = skipSequence(tmpAddedToCertIndex, tmpAddedToCert);
}
/* get the integer public modulus FIXME missing length check */
if (rc == 0) {
rc = getInteger(&tpm2bRsa.t.size, tpm2bRsa.t.buffer,
tmpAddedToCertIndex, tmpAddedToCert);
}
if (rc == 0) {
rc = addCertKeyRsa(x509Certificate,
&tpm2bRsa); /* certified public key */
}
/* skip the INTEGER public exponent - should not matter since it's the last item */
/* FIXME test for 010001 */
if (rc == 0) {
uint16_t dummy;
rc = getInteger(&dummy, NULL,
tmpAddedToCertIndex, tmpAddedToCert);
}
return rc;
}
/* addPubKeyEcc() adds the public key to the certificate. tmpAddedToCertIndex must point to the
public key.
*/
TPM_RC addPubKeyEcc(X509 *x509Certificate,
unsigned char *tmpAddedToCert,
uint16_t *tmpAddedToCertIndex)
{
TPM_RC rc = 0;
uint16_t dataLength;
TPMS_ECC_POINT tpmsEccPoint;
/* skip the SEQUENCE with the Signature Algorithm object identifier ecdsaWithSHA256 */
if (rc == 0) {
rc = copyType(0x30, NULL, NULL, /* NULL says to skip */
tmpAddedToCertIndex, tmpAddedToCert);
}
/* skip the SEQUENCE wrapper for the Subject Public Key Info */
if (rc == 0) {
rc = skipSequence(tmpAddedToCertIndex, tmpAddedToCert);
}
/* skip the SEQUENCE Public Key Algorithm */
if (rc == 0) {
rc = copyType(0x30, NULL, NULL, /* NULL says to skip */
tmpAddedToCertIndex, tmpAddedToCert);
}
/* skip the BIT STRING intoduction to the public key */
if (rc == 0) {
rc = skipBitString(&dataLength, tmpAddedToCertIndex, tmpAddedToCert);
}
/* the next bytes are the 04, x and y */
if (rc == 0) {
/* FIXME check that dataLength is 65 */
*tmpAddedToCertIndex += 1; /* skip the 0x04 compression byte */
tpmsEccPoint.x.t.size = 32;
memcpy(tpmsEccPoint.x.t.buffer, tmpAddedToCert + *tmpAddedToCertIndex, 32);
*tmpAddedToCertIndex += 32;
tpmsEccPoint.y.t.size = 32;
memcpy(tpmsEccPoint.y.t.buffer, tmpAddedToCert + *tmpAddedToCertIndex, 32);
*tmpAddedToCertIndex += 32;
rc = addCertKeyEcc(x509Certificate, &tpmsEccPoint);
}
return rc;
}
/* addSignatureRsa() copies the TPMT_SIGNATURE output of the TPM2_CertifyX509 command to the X509
certificate.
*/
TPM_RC addSignatureRsa(X509 *x509Certificate,
TPMT_SIGNATURE *tSignature)
{
TPM_RC rc = 0;
int irc;
X509_ALGOR *signatureAlgorithm = NULL;
X509_ALGOR *certSignatureAlgorithm = NULL;
ASN1_BIT_STRING *asn1Signature = NULL;
/* FIXME check sign length */
if (rc == 0) {
certSignatureAlgorithm = (X509_ALGOR *)X509_get0_tbs_sigalg(x509Certificate);
X509_get0_signature((OSSLCONST ASN1_BIT_STRING**)&asn1Signature,
(OSSLCONST X509_ALGOR **)&signatureAlgorithm,
x509Certificate);
}
/* set the algorithm in the top level structure */
if (rc == 0) {
X509_ALGOR_set0(signatureAlgorithm,
OBJ_nid2obj(NID_sha256WithRSAEncryption), V_ASN1_NULL, NULL);
}
/* set the algorithm in the to be signed structure */
if (rc == 0) {
X509_ALGOR_set0(certSignatureAlgorithm,
OBJ_nid2obj(NID_sha256WithRSAEncryption), V_ASN1_NULL, NULL);
}
/* ASN1_BIT_STRING x509Certificate->signature contains a BIT STRING with the RSA signature */
if (rc == 0) {
irc = ASN1_BIT_STRING_set(asn1Signature,
tSignature->signature.rsassa.sig.t.buffer,
tSignature->signature.rsassa.sig.t.size);
asn1Signature->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
asn1Signature->flags |= ASN1_STRING_FLAG_BITS_LEFT;
if (irc == 0) {
printf("addSignatureRsa: Error in ASN1_BIT_STRING_set for signature\n");
rc = TSS_RC_X509_ERROR;
}
}
return rc;
}
/* addSignatureEcc() copies the TPMT_SIGNATURE output of the TPM2_CertifyX509 command to the X509
certificate.
*/
TPM_RC addSignatureEcc(X509 *x509Certificate,
TPMT_SIGNATURE *tSignature)
{
TPM_RC rc = 0;
int irc;
X509_ALGOR *signatureAlgorithm = NULL;
X509_ALGOR *certSignatureAlgorithm = NULL;
ASN1_BIT_STRING *asn1Signature = NULL;
BIGNUM *rSig = NULL;
BIGNUM *sSig = NULL;
ECDSA_SIG *ecdsaSig = NULL;
unsigned char *ecdsaSigBin = NULL;
int ecdsaSigBinLength;
/* FIXME check sign length */
if (rc == 0) {
certSignatureAlgorithm = (X509_ALGOR *)X509_get0_tbs_sigalg(x509Certificate);
X509_get0_signature((OSSLCONST ASN1_BIT_STRING**)&asn1Signature,
(OSSLCONST X509_ALGOR **)&signatureAlgorithm,
x509Certificate);
}
/* set the algorithm in the top level structure */
if (rc == 0) {
X509_ALGOR_set0(signatureAlgorithm,
OBJ_nid2obj(NID_ecdsa_with_SHA256), V_ASN1_UNDEF, NULL);
}
/* set the algorithm in the to be signed structure */
if (rc == 0) {
X509_ALGOR_set0(certSignatureAlgorithm,
OBJ_nid2obj(NID_ecdsa_with_SHA256), V_ASN1_UNDEF, NULL);
}
/* ASN1_BIT_STRING x509Certificate->signature contains a sequence with two INTEGER, R and S */
/* construct DER and then ASN1_BIT_STRING_set into X509 */
if (rc == 0) {
rSig = BN_new();
if (rSig == NULL) {
printf("addSignatureEcc: BN_new() failed\n");
rc = TSS_RC_OUT_OF_MEMORY;
}
}
if (rc == 0) {
sSig = BN_new();
if (sSig == NULL) {
printf("addSignatureEcc: BN_new() failed\n");
rc = TSS_RC_OUT_OF_MEMORY;
}
}
if (rc == 0) {
rSig = BN_bin2bn(tSignature->signature.ecdsa.signatureR.b.buffer,
tSignature->signature.ecdsa.signatureR.b.size, rSig);
if (rSig == NULL) {
printf("addSignatureEcc: Error in BN_bin2bn\n");
rc = TSS_RC_BIGNUM;
}
}
if (rc == 0) {
sSig = BN_bin2bn(tSignature->signature.ecdsa.signatureS.b.buffer,
tSignature->signature.ecdsa.signatureS.b.size, sSig);
if (sSig == NULL) {
printf("addSignatureEcc: Error in BN_bin2bn\n");
rc = TSS_RC_BIGNUM;
}
}
if (rc == 0) {
ecdsaSig = ECDSA_SIG_new(); /* freed @1 */
if (ecdsaSig == NULL) {
printf("addSignatureEcc: ECDSA_SIG_new() failed\n");
rc = TSS_RC_OUT_OF_MEMORY;
}
}
if (rc == 0) {
irc = ECDSA_SIG_set0(ecdsaSig, rSig, sSig);
if (irc != 1) {
printf("addSignatureEcc: Error in ECDSA_SIG_set0\n");
rc = TSS_RC_X509_ERROR;
}
}
/* serialize the signature to DER */
if (rc == 0) {
ecdsaSigBinLength = i2d_ECDSA_SIG(ecdsaSig, &ecdsaSigBin); /* freed @2 */
if (ecdsaSigBinLength < 0) {
printf("addSignatureEcc: Error in signature serialization i2d_ECDSA_SIG()\n");
rc = TSS_RC_X509_ERROR;
}
}
/* add the DER signature to the certificate */
if (rc == 0) {
irc = ASN1_BIT_STRING_set(asn1Signature,
ecdsaSigBin,
ecdsaSigBinLength);
asn1Signature->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
asn1Signature->flags|=ASN1_STRING_FLAG_BITS_LEFT;
if (irc == 0) {
printf("addSignatureEcc: Error in ASN1_BIT_STRING_set for signature\n");
rc = TSS_RC_X509_ERROR;
}
}
/* freed by ECDSA_SIG_free */
if (ecdsaSig == NULL) {
BN_free(rSig);
BN_free(sSig);
}
ECDSA_SIG_free(ecdsaSig); /* @1 */
OPENSSL_free(ecdsaSigBin); /* @2 */
return rc;
}
/* getDataLength() checks the type, gets the length of the wrapper and following data */
TPM_RC getDataLength(uint8_t type, /* expected type */
uint16_t *wrapperLength, /* wrapper */
uint16_t *dataLength, /* data */
uint16_t *certificateDerIndex,
uint8_t *certificateDer)
{
TPM_RC rc = 0;
uint32_t i = 0;
uint16_t lengthLength = 0; /* number of length bytes */
/* validate the wrapper type */
if (rc == 0) {
if (certificateDer[*certificateDerIndex] != type) {
printf("getDataLength: index %u expect %02x actual %02x\n",
*certificateDerIndex, type, certificateDer[*certificateDerIndex]);
rc = TSS_RC_X509_ERROR;
}
}
/* get the length */
if (rc == 0) {
/* long form length starts with the 'length of the length' */
if ((certificateDer[*certificateDerIndex + 1] & 0x80)) {
lengthLength = certificateDer[*certificateDerIndex + 1] & 0x7f;
if (lengthLength <= sizeof(*dataLength)) {
*dataLength = 0;
for (i = 0 ; i < lengthLength ; i++) {
*dataLength <<= (i * 8);
*dataLength += certificateDer[*certificateDerIndex + 2 + i];
}
}
else {
printf("getDataLength: lengthLength %u too large for uint16_t\n", lengthLength);
rc = TSS_RC_X509_ERROR;
}
}
/* short form length is in byte following type */
else {
*dataLength = certificateDer[*certificateDerIndex + 1] & 0x7f;
}
}
if (rc == 0) {
*wrapperLength = 2 + lengthLength;
if (verbose) printf("getDataLength: wrapperLength %u dataLength %u\n",
*wrapperLength, *dataLength);
}
return rc;
}
/* skipSequence() moves the certificateDerIndex past the SEQUENCE and its length. I.e., it just
skips the wrapper, not the contents
*/
TPM_RC skipSequence(uint16_t *certificateDerIndex, uint8_t *certificateDer)
{
TPM_RC rc = 0;
uint16_t wrapperLength;
uint16_t dataLength;
if (rc == 0) {
rc = getDataLength(0x30, /* variable length SEQUENCE */
&wrapperLength,
&dataLength,
certificateDerIndex, certificateDer);
}
if (rc == 0) {
*certificateDerIndex += wrapperLength;
}
return rc;
}
/* skipBitString() moves the certificateDerIndex past the BIT STRING, its length, and its padding,
not the contents
*/
TPM_RC skipBitString(uint16_t *dataLength,
uint16_t *certificateDerIndex, uint8_t *certificateDer)
{
TPM_RC rc = 0;
uint16_t wrapperLength;
if (rc == 0) {
rc = getDataLength(0x03, /* BIT STRING */
&wrapperLength,
dataLength,
certificateDerIndex, certificateDer);
}
if (rc == 0) {
*certificateDerIndex += wrapperLength;
*certificateDerIndex += 1; /* BIT STRING padding */
}
return rc;
}
/* copyType() copies the type at certificateDerIndex to partialCertificateDer.
certificateDerIndex and partialCertificateDerLength are updated
*/
TPM_RC copyType(uint8_t type, /* expected type */
uint16_t *partialCertificateDerLength, uint8_t *partialCertificateDer,
uint16_t *certificateDerIndex, uint8_t *certificateDer)
{
TPM_RC rc = 0;
uint16_t wrapperLength = 0;
uint16_t dataLength = 0;
if (rc == 0) {
rc = getDataLength(type,
&wrapperLength,
&dataLength,
certificateDerIndex, certificateDer);
}
if (rc == 0) {
if (partialCertificateDer != NULL) {
memcpy(partialCertificateDer + *partialCertificateDerLength,
&(certificateDer[*certificateDerIndex]),
wrapperLength + dataLength);
*partialCertificateDerLength += wrapperLength + dataLength;
}
*certificateDerIndex += wrapperLength + dataLength;
}
return rc;
}
/* getInteger() copies the INTEGER data (not including the wrapper) to integerStream.
certificateDerIndex is updated.
*/
TPM_RC getInteger(uint16_t *integerDataLength, unsigned char *integerStream,
uint16_t *certificateDerIndex, unsigned char *certificateDer)
{
TPM_RC rc = 0;
uint16_t wrapperLength = 0;
if (rc == 0) {
rc = getDataLength(0x02, /* INTEGER */
&wrapperLength,
integerDataLength,
certificateDerIndex, certificateDer);
}
if (rc == 0) {
if (integerStream != NULL) {
memcpy(integerStream,
certificateDer + *certificateDerIndex + wrapperLength,
*integerDataLength);
}
*certificateDerIndex += wrapperLength + *integerDataLength;
}
return rc;
}
/* prependSequence() shifts the DER down and back fills the SEQUENCE and length */
TPM_RC prependSequence(uint16_t *partialCertificateDerLength, uint8_t *partialCertificateDer)
{
TPM_RC rc = 0;
uint16_t prefixLength;
uint16_t lengthLength = 0;
uint16_t i = 0;
if (verbose) printf("prependSequence: total length %u %04x\n",
*partialCertificateDerLength, *partialCertificateDerLength);
/* calculate the number of prepended bytes */
if (rc == 0) {
/* long form length when greater than 7f */
if ((*partialCertificateDerLength) > 0x7f) {
lengthLength = (*partialCertificateDerLength / 0x100) + 1; /* +1 to round up */
prefixLength = 2 + lengthLength; /* SEQUENCE + length of length + length bytes */
}
/* short form length when up to 7f */
else {
prefixLength = 2; /* SEQUENCE + length byte */
}
}
/* shift the partialCertificateDer down by prefix length */
if (rc == 0) {
memmove(partialCertificateDer + prefixLength,
partialCertificateDer,
*partialCertificateDerLength);
}
/* construct the prefix */
if (rc == 0) {
partialCertificateDer[0] = 0x30; /* SEQUENCE */
/* long form length */
if (lengthLength > 0) {
partialCertificateDer[1] = 0x80 + lengthLength; /* byte 1 bit 7 set for long form */
for (i = 0 ; i < lengthLength ; i++) { /* start at byte 2 */
partialCertificateDer[2 + i] = /* add length bytes */
(*partialCertificateDerLength >> ((lengthLength - i - 1) * 8)) & 0xff;
}
}
/* short form length */
else {
/* just length for short form, cast safe bacause of above test */
partialCertificateDer[1] = (uint8_t)*partialCertificateDerLength;
}
*partialCertificateDerLength += prefixLength; /* adjust the total length of the DER */
}
return rc;
}
static void printUsage(void)
{
printf("\n");
printf("certifyx509\n");
printf("\n");
printf("Runs TPM2_Certifyx509\n");
printf("\n");
printf("\t-ho\tobject handle\n");
printf("\t[-pwdo\tpassword for object (default empty)]\n");
printf("\t-hk\tcertifying key handle\n");
printf("\t[-pwdk\tpassword for key (default empty)]\n");
printf("\t[-halg\t(sha1, sha256, sha384 sha512) (default sha256)]\n");
printf("\t[-salg\tsignature algorithm (rsa, ecc) (default rsa)]\n");
printf("\t[-ku\tX509 key usage - string - comma separated, no spaces]\n");
printf("\t[-iob\tTPMA_OBJECT - 4 byte hex]\n");
printf("\t\te.g. sign: critical,digitalSignature,keyCertSign,cRLSign (default)\n");
printf("\t\te.g. decrypt: critical,dataEncipherment,keyAgreement,encipherOnly,decipherOnly\n");
printf("\t\te.g. fixedTPM: critical,nonRepudiation\n");
printf("\t\te.g. parent (restrict decrypt): critical,keyEncipherment\n");
printf("\t[-bit\tbit in partialCertificate to toggle]\n");
printf("\t[-sub\tsubject same as issuer for self signed (root) certificate]\n");
printf("\t[-opc\tpartial certificate file name (default do not save)]\n");
printf("\t[-oa\taddedToCertificate file name (default do not save)]\n");
printf("\t[-otbs\tsigned tbsDigest file name (default do not save)]\n");
printf("\t[-os\tsignature file name (default do not save)]\n");
printf("\t[-ocert\t reconstructed certificate file name (default do not save)]\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);
}
#endif /* TPM_TSS_MBEDTLS */
#ifdef TPM_TSS_MBEDTLS
int verbose;
int main(int argc, char *argv[])
{
argc = argc;
argv = argv;
printf("certifyx509 not supported with mbedtls yet\n");
return 0;
}
#endif /* TPM_TSS_MBEDTLS */