diff options
Diffstat (limited to 'roms/skiboot/libstb/tss2/ibmtpm20tss/utils/certifyx509.c')
-rw-r--r-- | roms/skiboot/libstb/tss2/ibmtpm20tss/utils/certifyx509.c | 1497 |
1 files changed, 1497 insertions, 0 deletions
diff --git a/roms/skiboot/libstb/tss2/ibmtpm20tss/utils/certifyx509.c b/roms/skiboot/libstb/tss2/ibmtpm20tss/utils/certifyx509.c new file mode 100644 index 000000000..ace43d0c4 --- /dev/null +++ b/roms/skiboot/libstb/tss2/ibmtpm20tss/utils/certifyx509.c @@ -0,0 +1,1497 @@ +/********************************************************************************/ +/* */ +/* 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 */ |