You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1453 lines
50 KiB
1453 lines
50 KiB
From c93d780442052ae113871f4033d788a5bbe288fa Mon Sep 17 00:00:00 2001 |
|
From: Ken Goldman <kgoldman@us.ibm.com> |
|
Date: Mon, 23 Aug 2021 16:09:41 -0400 |
|
Subject: [PATCH 1/7] utils: Update certifyx509 for Openssl 3.0.0 |
|
|
|
i2d_x509 no longer accepts a partial structure. Therefore, replace |
|
the input and output parsers with the ASN.1 parsing macros. |
|
Eliminated the custom DER parsing. Set the version from the TPM |
|
output rather than hard coding to v3. |
|
|
|
Add x509 validity time compatibility functions to cryptutils.c |
|
|
|
Add -check_ss_sig to the regression test because openssl verify does |
|
not verify the signature on self signed certificates. |
|
|
|
Signed-off-by: Ken Goldman <kgoldman@us.ibm.com> |
|
--- |
|
utils/certifyx509.c | 952 +++++++++++++------------------------ |
|
utils/cryptoutils.c | 32 +- |
|
utils/cryptoutils.h | 5 +- |
|
utils/regtests/testx509.sh | 9 +- |
|
4 files changed, 365 insertions(+), 633 deletions(-) |
|
|
|
diff --git a/utils/certifyx509.c b/utils/certifyx509.c |
|
index 7e8ba8d..ed42ac0 100644 |
|
--- a/utils/certifyx509.c |
|
+++ b/utils/certifyx509.c |
|
@@ -4,7 +4,7 @@ |
|
/* Written by Ken Goldman */ |
|
/* IBM Thomas J. Watson Research Center */ |
|
/* */ |
|
-/* (c) Copyright IBM Corporation 2019 - 2020. */ |
|
+/* (c) Copyright IBM Corporation 2019 - 2021. */ |
|
/* */ |
|
/* All rights reserved. */ |
|
/* */ |
|
@@ -50,6 +50,11 @@ |
|
#include <string.h> |
|
#include <stdint.h> |
|
|
|
+#include <openssl/asn1.h> |
|
+#include <openssl/asn1t.h> |
|
+#include <openssl/x509.h> |
|
+#include <openssl/x509v3.h> |
|
+ |
|
#include "cryptoutils.h" |
|
|
|
#ifndef TPM_TSS_MBEDTLS |
|
@@ -64,9 +69,74 @@ |
|
/* NOTE: This is currently openssl only. */ |
|
#include <ekutils.h> |
|
|
|
+/* definition of the partial certificate, from Part 3 TPM2_CertifyX509. |
|
+ 1) Signature Algorithm Identifier (optional) |
|
+ 2) Issuer (mandatory) |
|
+ 3) Validity (mandatory) |
|
+ 4) Subject Name (mandatory) |
|
+ 5) Extensions (mandatory) |
|
+*/ |
|
+ |
|
+typedef struct { |
|
+ ASN1_TIME *notBefore; |
|
+ ASN1_TIME *notAfter; |
|
+} TPM_PARTIAL_CERT_VALIDITY; |
|
+ |
|
+/* partial certificate TPM input parameter entire structure */ |
|
+typedef struct { |
|
+ X509_ALGOR *algorithm; /* signature algorithm */ |
|
+ X509_NAME *issuer; |
|
+ TPM_PARTIAL_CERT_VALIDITY *validity; |
|
+ X509_NAME *subject; |
|
+ STACK_OF(X509_EXTENSION) *extensions; |
|
+} TPM_PARTIAL_CERT; |
|
+ |
|
+ASN1_SEQUENCE(TPM_PARTIAL_CERT_VALIDITY) = { |
|
+ ASN1_SIMPLE(TPM_PARTIAL_CERT_VALIDITY, notBefore, ASN1_TIME), |
|
+ ASN1_SIMPLE(TPM_PARTIAL_CERT_VALIDITY, notAfter, ASN1_TIME), |
|
+} ASN1_SEQUENCE_END(TPM_PARTIAL_CERT_VALIDITY) |
|
+ |
|
+/* the signature algorithm is optional while the extension list is mandatory */ |
|
+ASN1_SEQUENCE(TPM_PARTIAL_CERT) = { |
|
+ ASN1_OPT(TPM_PARTIAL_CERT, algorithm, X509_ALGOR), |
|
+ ASN1_SIMPLE(TPM_PARTIAL_CERT, issuer, X509_NAME), |
|
+ ASN1_SIMPLE(TPM_PARTIAL_CERT, validity, TPM_PARTIAL_CERT_VALIDITY), |
|
+ ASN1_SIMPLE(TPM_PARTIAL_CERT, subject, X509_NAME), |
|
+ ASN1_EXP_SEQUENCE_OF(TPM_PARTIAL_CERT, extensions, X509_EXTENSION, 3), |
|
+} ASN1_SEQUENCE_END(TPM_PARTIAL_CERT) |
|
+ |
|
+DECLARE_ASN1_FUNCTIONS(TPM_PARTIAL_CERT) |
|
+IMPLEMENT_ASN1_FUNCTIONS(TPM_PARTIAL_CERT) |
|
+ |
|
+/* add to signature TPM output parameter */ |
|
+ |
|
+typedef struct { |
|
+ ASN1_INTEGER *version; |
|
+ ASN1_INTEGER *serialNumber; |
|
+ X509_ALGOR *signatureAlgorithm; |
|
+ X509_PUBKEY *key; |
|
+} TPM_ADDTOCERT; |
|
+ |
|
+ASN1_SEQUENCE(TPM_ADDTOCERT) = { |
|
+ ASN1_EXP_OPT(TPM_ADDTOCERT, version, ASN1_INTEGER, 0), |
|
+ ASN1_SIMPLE(TPM_ADDTOCERT, serialNumber, ASN1_INTEGER), |
|
+ ASN1_SIMPLE(TPM_ADDTOCERT, signatureAlgorithm, X509_ALGOR), |
|
+ ASN1_SIMPLE(TPM_ADDTOCERT, key, X509_PUBKEY), |
|
+} ASN1_SEQUENCE_END(TPM_ADDTOCERT) |
|
+ |
|
+DECLARE_ASN1_FUNCTIONS(TPM_ADDTOCERT) |
|
+IMPLEMENT_ASN1_FUNCTIONS(TPM_ADDTOCERT) |
|
+ |
|
static void printUsage(void); |
|
|
|
-TPM_RC createPartialCertificate(X509 *x509Certificate, |
|
+TPM_RC addPartialCertExtension(TPM_PARTIAL_CERT *partialCertificate, |
|
+ X509 *x509Certificate, |
|
+ int nid, const char *value); |
|
+TPM_RC addPartialCertExtensionTpmaOid(TPM_PARTIAL_CERT *partialCertificate, |
|
+ X509 *x509Certificate, |
|
+ uint32_t tpmaObject); |
|
+TPM_RC createPartialCertificate(TPM_PARTIAL_CERT *certificate, |
|
+ X509 *x509Certificate, |
|
uint8_t *partialCertificateDer, |
|
uint16_t *partialCertificateDerLength, |
|
size_t partialCertificateDerSize, |
|
@@ -74,22 +144,11 @@ TPM_RC createPartialCertificate(X509 *x509Certificate, |
|
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, |
|
TPMI_ALG_HASH halg, |
|
TPMI_ALG_SIG_SCHEME scheme, |
|
- TPMI_ECC_CURVE curveID, |
|
- 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_ADDTOCERT *addToCert, |
|
+ TPMT_SIGNATURE *tSignature); |
|
TPM_RC addSignatureRsa(X509 *x509Certificate, |
|
TPMI_ALG_HASH halg, |
|
TPMT_SIGNATURE *tSignature); |
|
@@ -97,38 +156,10 @@ TPM_RC addSignatureRsa(X509 *x509Certificate, |
|
TPM_RC addSignatureEcc(X509 *x509Certificate, |
|
TPMI_ALG_HASH halg, |
|
TPMT_SIGNATURE *signature); |
|
-TPM_RC addPubKeyEcc(X509 *x509Certificate, |
|
- unsigned char *tmpAddedToCert, |
|
- uint16_t *tmpAddedToCertIndex, |
|
- TPMI_ECC_CURVE curveID); |
|
#endif /* TPM_TSS_NOECC */ |
|
-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; |
|
@@ -145,8 +176,8 @@ int main(int argc, char *argv[]) |
|
TPMI_ALG_HASH halg = TPM_ALG_SHA256; |
|
unsigned int bit = 0; |
|
int testBit = FALSE; |
|
- const char *keyPassword = NULL; |
|
- const char *objectPassword = NULL; |
|
+ const char *keyPassword = NULL; |
|
+ const char *objectPassword = NULL; |
|
const char *outPartialCertificateFilename = NULL; |
|
const char *outCertificateFilename = NULL; |
|
const char *addedToCertificateFilename = NULL; |
|
@@ -167,6 +198,8 @@ int main(int argc, char *argv[]) |
|
X509 *x509Certificate = NULL; |
|
unsigned char *x509Der = NULL; |
|
uint32_t x509DerLength = 0; |
|
+ TPM_PARTIAL_CERT *partialCertificate = NULL; |
|
+ TPM_ADDTOCERT *addToCert = NULL; |
|
|
|
setvbuf(stdout, 0, _IONBF, 0); /* output may be going through pipe to log file */ |
|
TSS_SetProperty(NULL, TPM_TRACE_LEVEL, "1"); |
|
@@ -453,9 +486,8 @@ int main(int argc, char *argv[]) |
|
} |
|
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. */ |
|
+ /* initialize a new, empty X509 structure. It will be used to reform the certificate from |
|
+ the response parameters. */ |
|
if (rc == 0) { |
|
x509Certificate = X509_new(); /* freed @1 */ |
|
if (x509Certificate == NULL) { |
|
@@ -463,9 +495,19 @@ int main(int argc, char *argv[]) |
|
rc = TSS_RC_OUT_OF_MEMORY; |
|
} |
|
} |
|
- /* form partial certificate */ |
|
+ /* initialize a new, empty TPM_PARTIAL_CERT structure. It will be used to form the |
|
+ partialCertificate command parameter */ |
|
+ if (rc == 0) { |
|
+ partialCertificate = TPM_PARTIAL_CERT_new(); /* freed @2 */ |
|
+ if (partialCertificate == NULL) { |
|
+ printf("main: Error in TPM_PARTIAL_CERT_new\n"); |
|
+ rc = TSS_RC_OUT_OF_MEMORY; |
|
+ } |
|
+ } |
|
+ /* form partial certificate and populate the X509 certificate with the values */ |
|
if (rc == 0) { |
|
- rc = createPartialCertificate(x509Certificate, |
|
+ rc = createPartialCertificate(partialCertificate, |
|
+ x509Certificate, |
|
in.partialCertificate.t.buffer, |
|
&in.partialCertificate.b.size, |
|
sizeof(in.partialCertificate.t.buffer), |
|
@@ -474,6 +516,7 @@ int main(int argc, char *argv[]) |
|
addTpmaObject, |
|
subeqiss); |
|
} |
|
+ /* for debug testing */ |
|
if ((rc == 0) && (testBit)) { |
|
unsigned int bitInByte = bit % 8; |
|
unsigned int byteInDer = bit / 8; |
|
@@ -481,7 +524,7 @@ int main(int argc, char *argv[]) |
|
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]); |
|
} |
|
@@ -530,17 +573,22 @@ int main(int argc, char *argv[]) |
|
printf("%s%s%s\n", msg, submsg, num); |
|
rc = EXIT_FAILURE; |
|
} |
|
- /* write response parameters for debug */ |
|
+ /* |
|
+ write response parameters for debug |
|
+ */ |
|
+ /* added to certificate */ |
|
if ((rc == 0) && (addedToCertificateFilename != NULL)) { |
|
rc = TSS_File_WriteBinaryFile(out.addedToCertificate.t.buffer, |
|
out.addedToCertificate.t.size, |
|
addedToCertificateFilename); |
|
} |
|
+ /* to be signed digest */ |
|
if ((rc == 0) && (tbsDigestFilename != NULL)) { |
|
rc = TSS_File_WriteBinaryFile(out.tbsDigest.t.buffer, |
|
out.tbsDigest.t.size, |
|
tbsDigestFilename); |
|
} |
|
+ /* signature */ |
|
if ((rc == 0) && (signatureFilename != NULL)) { |
|
rc = TSS_File_WriteStructure(&out.signature, |
|
(MarshalFunction_t)TSS_TPMT_SIGNATURE_Marshalu, |
|
@@ -549,11 +597,21 @@ int main(int argc, char *argv[]) |
|
if (rc == 0) { |
|
if (verbose) TSS_TPMT_SIGNATURE_Print(&out.signature, 0); |
|
} |
|
- /* reform the signed certificate from the original input plus the response parameters */ |
|
+ /* convert the TPM output addedToCertificate DER to the OpenSSL structure */ |
|
+ if (rc == 0) { |
|
+ const unsigned char *tmpptr = out.addedToCertificate.t.buffer; |
|
+ addToCert = d2i_TPM_ADDTOCERT(NULL, /* freed @3 */ |
|
+ &tmpptr, out.addedToCertificate.t.size); |
|
+ if (addToCert == NULL) { |
|
+ printf("d2i_TPM_ADDTOCERT failed %p\n", addToCert); |
|
+ rc = EXIT_FAILURE; |
|
+ } |
|
+ } |
|
+ /* reform the signed certificate from the original X509 input plus the response parameters */ |
|
if (rc == 0) { |
|
rc = reformCertificate(x509Certificate, |
|
- halg, scheme, curveID, |
|
- &out.addedToCertificate, |
|
+ halg, scheme, |
|
+ addToCert, |
|
&out.signature); |
|
} |
|
if (rc == 0) { |
|
@@ -569,7 +627,8 @@ int main(int argc, char *argv[]) |
|
if (x509Certificate != NULL) { |
|
X509_free(x509Certificate); /* @1 */ |
|
} |
|
- free(x509Der); /* @2 */ |
|
+ free(x509Der); /* @2 */ |
|
+ free(addToCert); /* @3 */ |
|
return rc; |
|
} |
|
|
|
@@ -587,7 +646,7 @@ char *issuerEntries[] = { |
|
"IBM" , |
|
NULL , |
|
"CA" , |
|
- NULL |
|
+ NULL |
|
}; |
|
|
|
char *subjectEntries[] = { |
|
@@ -597,22 +656,23 @@ char *subjectEntries[] = { |
|
"IBM" , |
|
NULL , |
|
"Subject" , |
|
- NULL |
|
+ 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. |
|
+/* createPartialCertificate() forms the partialCertificate DER. It starts with an empty X509 and |
|
+ TPM_PARTIAL_CERT structures. It adds the needed parameters to both structures. It then |
|
+ serializes the TPM_PARTIAL_CERT structure to partialCertificateDer; |
|
|
|
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 */ |
|
+TPM_RC createPartialCertificate(TPM_PARTIAL_CERT *partialCertificate, /* input / output */ |
|
+ X509 *x509Certificate, /* input / output */ |
|
uint8_t *partialCertificateDer, /* output */ |
|
uint16_t *partialCertificateDerLength, |
|
- size_t partialCertificateDerSize, |
|
+ size_t partialCertificateDerSize, /* input, size of |
|
+ partialCertificateDer */ |
|
const char *keyUsage, |
|
uint32_t tpmaObject, |
|
int addTpmaObject, |
|
@@ -626,40 +686,31 @@ TPM_RC createPartialCertificate(X509 *x509Certificate, /* input / output */ |
|
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; |
|
+ ASN1_TIME *notBefore = NULL; |
|
+ ASN1_TIME *notAfter = NULL; |
|
+ uint8_t *tmpPartialDer = NULL; /* for the i2d */ |
|
|
|
- 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, /* freed @1 */ |
|
+ (unsigned long)issuerEntriesSize); |
|
+ rc = createX509Name(&partialCertificate->issuer, /* freed @1 */ |
|
issuerEntriesSize, |
|
issuerEntries); |
|
} |
|
if (rc == 0) { |
|
- irc = X509_set_issuer_name(x509Certificate, x509IssuerName); |
|
+ irc = X509_set_issuer_name(x509Certificate, partialCertificate->issuer); |
|
if (irc != 1) { |
|
printf("createPartialCertificate: Error setting issuer\n"); |
|
rc = TSS_RC_X509_ERROR; |
|
} |
|
} |
|
- /* add validity */ |
|
+ /* |
|
+ validity before |
|
+ */ |
|
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 */ |
|
+ /* set to today */ |
|
+ arc = X509_gmtime_adj(partialCertificate->validity->notBefore ,0L); |
|
if (arc == NULL) { |
|
printf("createPartialCertificate: Error setting notBefore time\n"); |
|
rc = TSS_RC_X509_ERROR; |
|
@@ -667,20 +718,39 @@ TPM_RC createPartialCertificate(X509 *x509Certificate, /* input / output */ |
|
} |
|
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 */ |
|
+ notBefore = X509_get_notBefore(x509Certificate); |
|
+ irc = X509_set1_notBefore(x509Certificate, partialCertificate->validity->notBefore); |
|
+ if (irc == 0) { |
|
+ printf("createPartialCertificate: Error setting notBefore time\n"); |
|
+ rc = TSS_RC_X509_ERROR; |
|
+ } |
|
+ } |
|
+ /* |
|
+ validity after |
|
+ */ |
|
+ if (rc == 0) { |
|
+ /* set to duration */ |
|
+ arc = X509_gmtime_adj(partialCertificate->validity->notAfter, CERT_DURATION); |
|
if (arc == NULL) { |
|
printf("createPartialCertificate: Error setting notAfter time\n"); |
|
rc = TSS_RC_X509_ERROR; |
|
} |
|
} |
|
+ if (rc == 0) { |
|
+ notAfter = X509_get_notAfter(x509Certificate); |
|
+ irc = X509_set1_notAfter(x509Certificate,partialCertificate->validity->notAfter); |
|
+ if (irc == 0) { |
|
+ 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, /* freed @2 */ |
|
+ rc = createX509Name(&partialCertificate->subject, /* freed @2 */ |
|
subjectEntriesSize, |
|
subjectEntries); |
|
} |
|
@@ -688,13 +758,13 @@ TPM_RC createPartialCertificate(X509 *x509Certificate, /* input / output */ |
|
else { |
|
if (verbose) printf("createPartialCertificate: Adding subject (issuer), size %lu\n", |
|
(unsigned long)issuerEntriesSize); |
|
- rc = createX509Name(&x509SubjectName, /* freed @2 */ |
|
+ rc = createX509Name(&partialCertificate->subject, /* freed @2 */ |
|
issuerEntriesSize, |
|
issuerEntries); |
|
} |
|
} |
|
if (rc == 0) { |
|
- irc = X509_set_subject_name(x509Certificate, x509SubjectName); |
|
+ irc = X509_set_subject_name(x509Certificate, partialCertificate->subject); |
|
if (irc != 1) { |
|
printf("createPartialCertificate: Error setting subject\n"); |
|
rc = TSS_RC_X509_ERROR; |
|
@@ -703,109 +773,179 @@ TPM_RC createPartialCertificate(X509 *x509Certificate, /* input / output */ |
|
/* 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); |
|
+ rc = addPartialCertExtension(partialCertificate, |
|
+ 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); |
|
+ rc = addPartialCertExtensionTpmaOid(partialCertificate, |
|
+ x509Certificate, |
|
+ tpmaObject); |
|
} |
|
} |
|
- /* convertX509ToDer() serializes the openSSL X509 structure to a DER certificate stream */ |
|
+ /* serialize the openSSL partial certificate structure to a DER stream */ |
|
+ if (rc == 0) { |
|
+ *partialCertificateDerLength = |
|
+ (uint16_t)i2d_TPM_PARTIAL_CERT(partialCertificate, |
|
+ &tmpPartialDer); /* freed @3 */ |
|
+ } |
|
+ /* check the i2d size, and copy the DER to the TPM input parameter */ |
|
if (rc == 0) { |
|
- rc = convertX509ToDer(&certificateDerLength, |
|
- &certificateDer, /* freed @4 */ |
|
- x509Certificate); /* input */ |
|
+ if (*partialCertificateDerLength <= partialCertificateDerSize) { |
|
+ memcpy(partialCertificateDer, tmpPartialDer, *partialCertificateDerLength); |
|
+ } |
|
+ else { |
|
+ printf("createPartialCertificate: Partial cert size %u too large\n", |
|
+ *partialCertificateDerLength); |
|
+ rc = TSS_RC_X509_ERROR; |
|
+ } |
|
} |
|
- /* for debug. The structure is incomplete and so will trace with errors */ |
|
+#if 0 |
|
+ /* for debug. The X509 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 */ |
|
+#endif |
|
+ X509_NAME_free(x509IssuerName); /* @1 */ |
|
+ X509_NAME_free(x509SubjectName); /* @2 */ |
|
+ free(tmpPartialDer); /* @3 */ |
|
+ return rc; |
|
+} |
|
+ |
|
+/* addPartialCertExtension() adds the extension type 'nid' to the partial certificate |
|
+ |
|
+ */ |
|
+ |
|
+TPM_RC addPartialCertExtension(TPM_PARTIAL_CERT *partialCertificate, |
|
+ X509 *x509Certificate, |
|
+ int nid, const char *value) |
|
+{ |
|
+ TPM_RC rc = 0; |
|
+ X509_EXTENSION *extension = NULL; /* freed @1 */ |
|
+ |
|
+ if (rc == 0) { |
|
+#if OPENSSL_VERSION_NUMBER < 0x10100000 |
|
+ /* the cast is required for the older openssl 1.0 API */ |
|
+ extension = X509V3_EXT_conf_nid(NULL, NULL, /* freed @1 */ |
|
+ nid, (char *)value); |
|
+#else |
|
+ extension = X509V3_EXT_conf_nid(NULL, NULL, /* freed @1 */ |
|
+ nid, value); |
|
+#endif |
|
+ if (extension == NULL) { |
|
+ printf("addPartialCertExtension: Error creating nid %i extension %s\n", |
|
+ nid, value); |
|
+ rc = -1; |
|
+ } |
|
+ } |
|
if (rc == 0) { |
|
- rc = TSS_File_WriteBinaryFile(certificateDer, certificateDerLength , "tmpx509i.bin"); |
|
+ STACK_OF(X509_EXTENSION) *src = |
|
+ X509v3_add_ext(&partialCertificate->extensions, |
|
+ extension, /* the extension to add */ |
|
+ -1); /* location - append */ |
|
+ if (src == NULL) { |
|
+ printf("addPartialCertExtension: Error adding nid %i extension %s\n", |
|
+ nid, value); |
|
+ } |
|
} |
|
-#endif |
|
- /* extract the partialCertificate DER from the X509 DER */ |
|
if (rc == 0) { |
|
- rc = convertCertToPartialCert(partialCertificateDerLength, |
|
- partialCertificateDer, /* output partial */ |
|
- certificateDerLength, |
|
- certificateDer); /* input X509 */ |
|
+ int irc = X509_add_ext(x509Certificate, |
|
+ 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 */ |
|
} |
|
- X509_NAME_free(x509IssuerName); /* @1 */ |
|
- X509_NAME_free(x509SubjectName); /* @2 */ |
|
- free(certificateDer); /* @4 */ |
|
return rc; |
|
} |
|
|
|
-/* addCertExtension() adds the tpmaObject extension oid to the X509 certificate |
|
+/* addPartialCertExtensionTpmaOid() adds the tpmaObject extension oid to the X509 certificate |
|
|
|
- */ |
|
+ */ |
|
|
|
-TPM_RC addCertExtensionTpmaOid(X509 *x509Certificate, uint32_t tpmaObject) |
|
+TPM_RC addPartialCertExtensionTpmaOid(TPM_PARTIAL_CERT *partialCertificate, |
|
+ 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; |
|
+ const uint8_t *tmpOidPtr; /* const for d2i_ASN1_OBJECT */ |
|
|
|
/* 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; |
|
+ ASN1_OCTET_STRING *osData = NULL; |
|
uint8_t *tmpOdPtr; |
|
uint32_t tpmaObjectNbo = htonl(tpmaObject); |
|
|
|
+ |
|
+ /* create the object */ |
|
if (rc == 0) { |
|
- tmpOidPtr = tpmaObjectOid; |
|
+ tmpOidPtr = tpmaObjectOid; |
|
object = d2i_ASN1_OBJECT(NULL, &tmpOidPtr, sizeof(tpmaObjectOid)); /* freed @2 */ |
|
if (object == NULL) { |
|
- printf("d2i_ASN1_OBJECT failed\n"); |
|
+ printf("addPartialCertExtensionTpmaOid: 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"); |
|
+ printf("addPartialCertExtensionTpmaOid: ASN1_OCTET_STRING_new failed\n"); |
|
rc = TSS_RC_X509_ERROR; |
|
} |
|
} |
|
+ /* copy the TPMA_OBJECT bytes to the BIT STRING place holder, set the result in the |
|
+ ASN1_OCTET_STRING */ |
|
if (rc == 0) { |
|
tmpOdPtr = tpmaObjectData; |
|
memcpy(tmpOdPtr + 3, &tpmaObjectNbo, sizeof(uint32_t)); |
|
ASN1_OCTET_STRING_set(osData, tmpOdPtr, sizeof (tpmaObjectData)); |
|
} |
|
+ /* create the extension with the TPMA_OBJECT in the ASN1_OBJECT */ |
|
if (rc == 0) { |
|
extension = X509_EXTENSION_create_by_OBJ(NULL, /* freed @1 */ |
|
object, |
|
- 0, /* int crit */ |
|
+ 0, /* int crit */ |
|
osData); |
|
if (extension == NULL) { |
|
- printf("X509_EXTENSION_create_by_OBJ failed\n"); |
|
+ printf("addPartialCertExtensionTpmaOid: X509_EXTENSION_create_by_OBJ failed\n"); |
|
rc = TSS_RC_X509_ERROR; |
|
} |
|
} |
|
+ /* append the extensions to the partial certificate stack */ |
|
+ if (rc == 0) { |
|
+ STACK_OF(X509_EXTENSION) *src = X509v3_add_ext(&partialCertificate->extensions, |
|
+ extension, /* the extension to add */ |
|
+ -1); /* location - append */ |
|
+ if (src == NULL) { |
|
+ printf("addPartialCertExtensionTpmaOid: Error adding oid to extension\n"); |
|
+ } |
|
+ } |
|
+ /* append the extensions to the X509 certificate */ |
|
if (rc == 0) { |
|
- int irc = X509_add_ext(x509Certificate, /* the certificate */ |
|
+ 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"); |
|
+ printf("addPartialCertExtensionTpmaOid: Error adding oid to extension\n"); |
|
} |
|
} |
|
if (extension != NULL) { |
|
X509_EXTENSION_free(extension); /* @1 */ |
|
} |
|
if (object != NULL) { |
|
- ASN1_OBJECT_free(object); /* @2 */ |
|
+ ASN1_OBJECT_free(object); /* @2 */ |
|
} |
|
if (osData != NULL) { |
|
ASN1_OCTET_STRING_free(osData); /* @3 */ |
|
@@ -813,327 +953,95 @@ TPM_RC addCertExtensionTpmaOid(X509 *x509Certificate, uint32_t tpmaObject) |
|
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. |
|
-*/ |
|
+/* reformCertificate() starts with the X509 certificate filled with the input partialCertificate |
|
+ parameter. It adds the output addedToCertificate and signature values to reform the X509 |
|
+ certificate that the TPM signed. */ |
|
|
|
TPM_RC reformCertificate(X509 *x509Certificate, |
|
TPMI_ALG_HASH halg, |
|
TPMI_ALG_SIG_SCHEME scheme, |
|
- TPMI_ECC_CURVE curveID, |
|
- TPM2B_MAX_BUFFER *addedToCertificate, |
|
+ TPM_ADDTOCERT *addToCert, |
|
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 (scheme == TPM_ALG_RSASSA) { |
|
- /* add public key algorithm and public key */ |
|
- if (rc == 0) { |
|
- rc = addPubKeyRsa(x509Certificate, |
|
- tmpAddedToCert, |
|
- &tmpAddedToCertIndex); |
|
- } |
|
- /* add certificate signature */ |
|
- if (rc == 0) { |
|
- rc = addSignatureRsa(x509Certificate, halg, tSignature); |
|
+ int irc; |
|
+ long versionl; |
|
+ EVP_PKEY *evpPubkey = NULL; /* EVP format public key to be certified */ |
|
+ |
|
+ /* version */ |
|
+#if OPENSSL_VERSION_NUMBER < 0x10100000 |
|
+ /* Older openssl does not has the uint64 function. This function is deprecated but OK since |
|
+ X509 certificates never have a negative version. */ |
|
+ if (rc == 0) { |
|
+ versionl= ASN1_INTEGER_get(addToCert->version); |
|
+ if (versionl < 0) { |
|
+ printf("reformCertificate: Error in ASN1_INTEGER_get version\n"); |
|
+ rc = TSS_RC_X509_ERROR; |
|
} |
|
} |
|
-#ifndef TPM_TSS_NOECC |
|
- else { /* scheme == TPM_ALG_ECDSA */ |
|
- /* add public key */ |
|
- if (rc == 0) { |
|
- rc = addPubKeyEcc(x509Certificate, |
|
- tmpAddedToCert, |
|
- &tmpAddedToCertIndex, |
|
- curveID); |
|
+#else |
|
+ if (rc == 0) { |
|
+ uint64_t version64; |
|
+ irc = ASN1_INTEGER_get_uint64(&version64, addToCert->version); |
|
+ if (irc != 1) { |
|
+ printf("reformCertificate: Error in ASN1_INTEGER_get_uint64 version\n"); |
|
+ rc = TSS_RC_X509_ERROR; |
|
} |
|
- /* add certificate signature */ |
|
- if (rc == 0) { |
|
- rc = addSignatureEcc(x509Certificate, halg, tSignature); |
|
+ else if (version64 > LONG_MAX) { |
|
+ printf("reformCertificate: Version out of range\n"); |
|
+ rc = TSS_RC_X509_ERROR; |
|
+ } |
|
+ else { |
|
+ versionl = (long)version64; |
|
} |
|
} |
|
-#endif /* TPM_TSS_NOECC */ |
|
- 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 */ |
|
+#endif |
|
if (rc == 0) { |
|
- x509SerialBN = BN_bin2bn(x509SerialBin, integerLength, x509SerialBN); /* freed @1 */ |
|
- if (x509SerialBN == NULL) { |
|
- printf("addSerialNumber: Error in serial number BN_bin2bn\n"); |
|
+ irc = X509_set_version(x509Certificate, versionl); |
|
+ if (irc != 1) { |
|
+ printf("reformCertificate: Error in X509_set_version\n"); |
|
rc = TSS_RC_X509_ERROR; |
|
} |
|
} |
|
- /* add it into the final certificate */ |
|
+ /* serial number */ |
|
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"); |
|
+ irc = X509_set_serialNumber(x509Certificate, addToCert->serialNumber); |
|
+ if (irc != 1) { |
|
+ printf("reformCertificate: Error in X509_set_serialNumber\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); |
|
- } |
|
+ /* public key including algorithm */ |
|
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; |
|
-} |
|
- |
|
-#ifndef TPM_TSS_NOECC |
|
-/* addPubKeyEcc() adds the public key to the certificate. tmpAddedToCertIndex must point to the |
|
- public key. |
|
- |
|
- Supports TPM_ECC_NIST_P256, TPM_ECC_NIST_P384. |
|
-*/ |
|
- |
|
- |
|
-TPM_RC addPubKeyEcc(X509 *x509Certificate, |
|
- unsigned char *tmpAddedToCert, |
|
- uint16_t *tmpAddedToCertIndex, |
|
- TPMI_ECC_CURVE curveID) |
|
-{ |
|
- TPM_RC rc = 0; |
|
- uint16_t dataLength; |
|
- uint16_t pointSize; |
|
- |
|
- /* skip the SEQUENCE with the Signature Algorithm object identifier ecdsaWithSHAnnn */ |
|
- 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); |
|
+ evpPubkey = X509_PUBKEY_get(addToCert->key); /* freed @1 */ |
|
+ if (evpPubkey == NULL) { |
|
+ printf("reformCertificate: X509_PUBKEY_get failed\n"); |
|
+ rc = TSS_RC_OUT_OF_MEMORY; |
|
+ } |
|
} |
|
if (rc == 0) { |
|
- switch(curveID) { |
|
- case TPM_ECC_NIST_P256: |
|
- pointSize = 256/8; |
|
- break; |
|
- case TPM_ECC_NIST_P384: |
|
- pointSize = 384/8; |
|
- break; |
|
- default: /* should never occur */ |
|
- printf("addPubKeyEcc: Bad curveID %04x\n", curveID); |
|
- rc = TSS_RC_BAD_SIGNATURE_ALGORITHM; |
|
- break; |
|
+ irc = X509_set_pubkey(x509Certificate, evpPubkey); |
|
+ if (irc != 1) { |
|
+ printf("reformCertificate: Error X509_set_pubkey failed\n"); |
|
+ rc = TSS_RC_X509_ERROR; |
|
} |
|
} |
|
- /* the next bytes are the 04, x and y */ |
|
+ /* add certificate signature */ |
|
if (rc == 0) { |
|
- TPMT_PUBLIC tpmtPublic; |
|
- |
|
- *tmpAddedToCertIndex += 1; /* skip the 0x04 compression byte */ |
|
- |
|
- tpmtPublic.unique.ecc.x.t.size = pointSize; |
|
- memcpy(tpmtPublic.unique.ecc.x.t.buffer, tmpAddedToCert + *tmpAddedToCertIndex, pointSize); |
|
- *tmpAddedToCertIndex += pointSize; |
|
- |
|
- |
|
- tpmtPublic.unique.ecc.y.t.size = pointSize; |
|
- memcpy(tpmtPublic.unique.ecc.y.t.buffer, tmpAddedToCert + *tmpAddedToCertIndex, pointSize); |
|
- *tmpAddedToCertIndex += pointSize; |
|
- |
|
- tpmtPublic.parameters.eccDetail.curveID = curveID; |
|
- rc = addCertKeyEccT(x509Certificate, &tpmtPublic); |
|
+ if (scheme == TPM_ALG_RSASSA) { |
|
+ if (rc == 0) { |
|
+ rc = addSignatureRsa(x509Certificate, halg, tSignature); |
|
+ } |
|
+ } |
|
+ else { /* scheme == TPM_ALG_ECDSA */ |
|
+ if (rc == 0) { |
|
+ rc = addSignatureEcc(x509Certificate, halg, tSignature); |
|
+ } |
|
+ } |
|
} |
|
+ EVP_PKEY_free(evpPubkey); /* @1 **/ |
|
return rc; |
|
} |
|
-#endif /* TPM_TSS_NOECC */ |
|
|
|
/* addSignatureRsa() copies the TPMT_SIGNATURE output of the TPM2_CertifyX509 command to the X509 |
|
certificate. |
|
@@ -1148,9 +1056,9 @@ TPM_RC addSignatureRsa(X509 *x509Certificate, |
|
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, |
|
@@ -1194,6 +1102,7 @@ TPM_RC addSignatureRsa(X509 *x509Certificate, |
|
} |
|
|
|
#ifndef TPM_TSS_NOECC |
|
+ |
|
/* addSignatureEcc() copies the TPMT_SIGNATURE output of the TPM2_CertifyX509 command to the X509 |
|
certificate. |
|
*/ |
|
@@ -1214,7 +1123,7 @@ TPM_RC addSignatureEcc(X509 *x509Certificate, |
|
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, |
|
@@ -1319,211 +1228,6 @@ TPM_RC addSignatureEcc(X509 *x509Certificate, |
|
} |
|
#endif /* TPM_TSS_NOECC */ |
|
|
|
-/* 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"); |
|
@@ -1550,7 +1254,7 @@ static void printUsage(void) |
|
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"); |
|
@@ -1563,7 +1267,7 @@ static void printUsage(void) |
|
printf("\t01\tcontinue\n"); |
|
printf("\t20\tcommand decrypt\n"); |
|
printf("\t40\tresponse encrypt\n"); |
|
- exit(1); |
|
+ exit(1); |
|
} |
|
|
|
#endif /* TPM_TSS_MBEDTLS */ |
|
diff --git a/utils/cryptoutils.c b/utils/cryptoutils.c |
|
index 7c4e931..eb5f0d2 100644 |
|
--- a/utils/cryptoutils.c |
|
+++ b/utils/cryptoutils.c |
|
@@ -4,7 +4,7 @@ |
|
/* Written by Ken Goldman */ |
|
/* IBM Thomas J. Watson Research Center */ |
|
/* */ |
|
-/* (c) Copyright IBM Corporation 2018 - 2020. */ |
|
+/* (c) Copyright IBM Corporation 2018 - 2021. */ |
|
/* */ |
|
/* All rights reserved. */ |
|
/* */ |
|
@@ -160,6 +160,36 @@ void RSA_get0_factors(const RSA *rsaKey, |
|
return; |
|
} |
|
|
|
+static int ossl_x509_set1_time(ASN1_TIME **ptm, const ASN1_TIME *tm); |
|
+ |
|
+int X509_set1_notBefore(X509 *x, const ASN1_TIME *tm) |
|
+{ |
|
+ if (x == NULL) |
|
+ return 0; |
|
+ return ossl_x509_set1_time(&x->cert_info->validity->notBefore, tm); |
|
+} |
|
+ |
|
+int X509_set1_notAfter(X509 *x, const ASN1_TIME *tm) |
|
+{ |
|
+ if (x == NULL) |
|
+ return 0; |
|
+ return ossl_x509_set1_time(&x->cert_info->validity->notAfter, tm); |
|
+} |
|
+ |
|
+static int ossl_x509_set1_time(ASN1_TIME **ptm, const ASN1_TIME *tm) |
|
+{ |
|
+ ASN1_TIME *in; |
|
+ in = *ptm; |
|
+ if (in != tm) { |
|
+ in = ASN1_STRING_dup(tm); |
|
+ if (in != NULL) { |
|
+ ASN1_TIME_free(*ptm); |
|
+ *ptm = in; |
|
+ } |
|
+ } |
|
+ return (in != NULL); |
|
+} |
|
+ |
|
#endif /* pre openssl 1.1 */ |
|
|
|
/* These functions are only required for OpenSSL 1.0.1 OpenSSL 1.0.2 has them, and the structures |
|
diff --git a/utils/cryptoutils.h b/utils/cryptoutils.h |
|
index c2ddc6c..03452de 100644 |
|
--- a/utils/cryptoutils.h |
|
+++ b/utils/cryptoutils.h |
|
@@ -4,7 +4,7 @@ |
|
/* Written by Ken Goldman */ |
|
/* IBM Thomas J. Watson Research Center */ |
|
/* */ |
|
-/* (c) Copyright IBM Corporation 2017 - 2019. */ |
|
+/* (c) Copyright IBM Corporation 2017 - 2021. */ |
|
/* */ |
|
/* All rights reserved. */ |
|
/* */ |
|
@@ -225,6 +225,9 @@ extern "C" { |
|
void RSA_get0_factors(const RSA *rsaKey, |
|
const BIGNUM **p, |
|
const BIGNUM **q); |
|
+ int X509_set1_notBefore(X509 *x, const ASN1_TIME *tm); |
|
+ int X509_set1_notAfter(X509 *x, const ASN1_TIME *tm); |
|
+ EVP_PKEY *X509_PUBKEY_get0(X509_PUBKEY *key); |
|
#endif /* pre openssl 1.1 */ |
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x10002000 |
|
diff --git a/utils/regtests/testx509.sh b/utils/regtests/testx509.sh |
|
index 813085f..5640985 100755 |
|
--- a/utils/regtests/testx509.sh |
|
+++ b/utils/regtests/testx509.sh |
|
@@ -73,8 +73,6 @@ do |
|
checkSuccess $? |
|
|
|
|
|
- # dumpasn1 -a -l -d tmpx509i.bin > tmpx509i1.dump |
|
- # dumpasn1 -a -l -d -hh tmpx509i.bin > tmpx509i1.dumphh |
|
# dumpasn1 -a -l -d tmppart1.bin > tmppart1.dump |
|
# dumpasn1 -a -l -d -hh tmppart1.bin > tmppart1.dumphh |
|
# dumpasn1 -a -l -d tmpadd1.bin > tmpadd1.dump |
|
@@ -88,7 +86,7 @@ do |
|
echo " INFO:" |
|
|
|
echo "Verify ${SALG[i]} self signed issuer root" |
|
- openssl verify -CAfile tmpx5091.pem tmpx5091.pem > run.out 2>&1 |
|
+ openssl verify -check_ss_sig -CAfile tmpx5091.pem tmpx5091.pem > run.out 2>&1 |
|
grep -q OK run.out |
|
checkSuccess $? |
|
|
|
@@ -96,8 +94,6 @@ do |
|
${PREFIX}certifyx509 -hk 80000001 -ho 80000002 -halg ${HALG[i]} -pwdk sig -pwdo sig -opc tmppart2.bin -os tmpsig2.bin -oa tmpadd2.bin -otbs tmptbs2.bin -ocert tmpx5092.bin ${SALG[i]} -iob 00040472 > run.out |
|
checkSuccess $? |
|
|
|
- # dumpasn1 -a -l -d tmpx509i.bin > tmpx509i2.dump |
|
- # dumpasn1 -a -l -d -hh tmpx509i.bin > tmpx509i2.dumphh |
|
# dumpasn1 -a -l -d tmppart2.bin > tmppart2.dump |
|
# dumpasn1 -a -l -d -hh tmppart2.bin > tmppart2.dumphhe |
|
# dumpasn1 -a -l -d tmpadd2.bin > tmpadd2.dump |
|
@@ -111,7 +107,7 @@ do |
|
echo " INFO:" |
|
|
|
echo "Verify ${SALG[i]} subject against issuer" |
|
- openssl verify -CAfile tmpx5091.pem tmpx5092.pem > run.out 2>&1 |
|
+ openssl verify -check_ss_sig -CAfile tmpx5091.pem tmpx5092.pem > run.out 2>&1 |
|
grep -q OK run.out |
|
checkSuccess $? |
|
|
|
@@ -333,7 +329,6 @@ rm -r tmpsig1.bin |
|
rm -r tmpx5091.bin |
|
rm -r tmpx5091.pem |
|
rm -r tmpx5092.pem |
|
-rm -r tmpx509i.bin |
|
rm -r tmppart2.bin |
|
rm -r tmpadd2.bin |
|
rm -r tmptbs2.bin |
|
-- |
|
2.34.1 |
|
|
|
|