283 lines
8.1 KiB
Diff
283 lines
8.1 KiB
Diff
From 22ecb8a2c00db7a53508d2106957e0c112a5a020 Mon Sep 17 00:00:00 2001
|
|
From: Petr Gotthard <petr.gotthard@centrum.cz>
|
|
Date: Tue, 31 Aug 2021 12:27:35 +0200
|
|
Subject: [PATCH 17/17] Generate partial X.509 certificate using own struct
|
|
|
|
The tpm2_certifyX509certutil.c:generate_partial_X509() creates a partial
|
|
(in fact, an incomplete) certificate, see Part 3, 18.8.1. The OpenSSL
|
|
team decided that starting from 3.0 the i2d should not create invalid
|
|
encodings, so we need to create an own ASN.1 structure for this.
|
|
|
|
The structure is adapted from
|
|
https://github.com/openssl/openssl/issues/16257#issuecomment-895448370.
|
|
|
|
Fixes: #2813
|
|
|
|
Signed-off-by: Petr Gotthard <petr.gotthard@centrum.cz>
|
|
---
|
|
tools/misc/tpm2_certifyX509certutil.c | 179 +++++++++-----------------
|
|
1 file changed, 59 insertions(+), 120 deletions(-)
|
|
|
|
diff --git a/tools/misc/tpm2_certifyX509certutil.c b/tools/misc/tpm2_certifyX509certutil.c
|
|
index 62ed644a..5eea08e8 100644
|
|
--- a/tools/misc/tpm2_certifyX509certutil.c
|
|
+++ b/tools/misc/tpm2_certifyX509certutil.c
|
|
@@ -8,6 +8,8 @@
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
+#include <openssl/asn1.h>
|
|
+#include <openssl/asn1t.h>
|
|
#include <openssl/x509.h>
|
|
#include <openssl/x509v3.h>
|
|
#include <openssl/bio.h>
|
|
@@ -15,6 +17,46 @@
|
|
#include "log.h"
|
|
#include "tpm2_tool.h"
|
|
|
|
+typedef struct {
|
|
+ ASN1_TIME *notBefore;
|
|
+ ASN1_TIME *notAfter;
|
|
+} TPM2_PARTIAL_CERT_VALIDITY;
|
|
+
|
|
+typedef struct {
|
|
+ X509_ALGOR *algorithm;
|
|
+ X509_NAME *issuer;
|
|
+ TPM2_PARTIAL_CERT_VALIDITY *validity;
|
|
+ X509_NAME *subject;
|
|
+ STACK_OF(X509_EXTENSION) *extensions;
|
|
+} TPM2_PARTIAL_CERT;
|
|
+
|
|
+ASN1_SEQUENCE(TPM2_PARTIAL_CERT_VALIDITY) = {
|
|
+ ASN1_SIMPLE(TPM2_PARTIAL_CERT_VALIDITY, notBefore, ASN1_TIME),
|
|
+ ASN1_SIMPLE(TPM2_PARTIAL_CERT_VALIDITY, notAfter, ASN1_TIME),
|
|
+} ASN1_SEQUENCE_END(TPM2_PARTIAL_CERT_VALIDITY)
|
|
+
|
|
+/* partialCertificate per Part 3, 18.8.1 */
|
|
+ASN1_SEQUENCE(TPM2_PARTIAL_CERT) = {
|
|
+ ASN1_OPT(TPM2_PARTIAL_CERT, algorithm, X509_ALGOR),
|
|
+ ASN1_SIMPLE(TPM2_PARTIAL_CERT, issuer, X509_NAME),
|
|
+ ASN1_SIMPLE(TPM2_PARTIAL_CERT, validity, TPM2_PARTIAL_CERT_VALIDITY),
|
|
+ ASN1_SIMPLE(TPM2_PARTIAL_CERT, subject, X509_NAME),
|
|
+ ASN1_EXP_SEQUENCE_OF(TPM2_PARTIAL_CERT, extensions, X509_EXTENSION, 3),
|
|
+} ASN1_SEQUENCE_END(TPM2_PARTIAL_CERT)
|
|
+
|
|
+IMPLEMENT_ASN1_FUNCTIONS(TPM2_PARTIAL_CERT)
|
|
+
|
|
+int i2d_TPM2_PARTIAL_CERT_bio(BIO *bp, const TPM2_PARTIAL_CERT *a)
|
|
+{
|
|
+ return ASN1_i2d_bio_of(TPM2_PARTIAL_CERT, i2d_TPM2_PARTIAL_CERT, bp, a);
|
|
+}
|
|
+
|
|
+int TPM2_add_ext(TPM2_PARTIAL_CERT *x, X509_EXTENSION *ex, int loc)
|
|
+{
|
|
+ return (X509v3_add_ext(&(x->extensions), ex, loc) != NULL);
|
|
+}
|
|
+
|
|
+
|
|
struct tpm_gen_partial_cert {
|
|
const char *out_path;
|
|
const char *valid_str;
|
|
@@ -95,80 +137,6 @@ static struct name_fields names[] = {
|
|
.def = "CA Unit" },
|
|
};
|
|
|
|
-static tool_rc fixup_cert(const char *cert) {
|
|
-
|
|
- int fd = open(cert, O_RDONLY);
|
|
- if (fd < 0) {
|
|
- LOG_ERR("open failed");
|
|
- return tool_rc_general_error;
|
|
- }
|
|
-
|
|
- struct stat fs;
|
|
- int ret = fstat(fd, &fs);
|
|
- if (ret < 0) {
|
|
- close(fd);
|
|
- return tool_rc_general_error;
|
|
- }
|
|
-
|
|
- ssize_t size = fs.st_size;
|
|
- if (size < 100 || size > 255) {
|
|
- LOG_ERR("Wrong cert size %zd", size);
|
|
- close(fd);
|
|
- return tool_rc_general_error; /* there is something wrong with this cert */
|
|
- }
|
|
-
|
|
- char* buf = calloc(1, size);
|
|
- if (!buf) {
|
|
- LOG_ERR("Alloc failed");
|
|
- close(fd);
|
|
- return tool_rc_general_error;
|
|
- }
|
|
-
|
|
- tool_rc rc = tool_rc_success;
|
|
- ret = read(fd, buf, size);
|
|
- close(fd);
|
|
- if (ret != size) {
|
|
- LOG_ERR("read failed");
|
|
- rc = tool_rc_general_error;
|
|
- goto out;
|
|
- }
|
|
-
|
|
- fd = open(cert, O_WRONLY | O_TRUNC);
|
|
- if (fd < 0) {
|
|
- LOG_ERR("second open failed");
|
|
- rc = tool_rc_general_error;
|
|
- goto out;
|
|
- }
|
|
-
|
|
- /* We need to skip one wrapping sequence (8 bytes) and one
|
|
- * sequence with one empty byte field at the end (5 bytes).
|
|
- * Fix the size here */
|
|
- buf[2] = size - 16;
|
|
-
|
|
- /* Write the external sequence with the fixed size */
|
|
- ret = write(fd, buf, 3);
|
|
- if (ret != 3) {
|
|
- LOG_ERR("write failed");
|
|
- rc = tool_rc_general_error;
|
|
- close(fd);
|
|
- goto out;
|
|
- }
|
|
-
|
|
- /* skip the wrapping sequence the write the rest
|
|
- * without the 5 bytes at the end */
|
|
- ret = write(fd, buf + 11, size - 16);
|
|
- close(fd);
|
|
- if (ret != size - 16) {
|
|
- LOG_ERR("second write failed");
|
|
- rc = tool_rc_general_error;
|
|
- }
|
|
-
|
|
-out:
|
|
- free(buf);
|
|
-
|
|
- return rc;
|
|
-}
|
|
-
|
|
static int populate_fields(X509_NAME *name, const char *opt) {
|
|
|
|
char *name_opt = strdup(opt);
|
|
@@ -228,19 +196,14 @@ static tool_rc generate_partial_X509() {
|
|
}
|
|
|
|
X509_EXTENSION *extv3 = NULL;
|
|
- X509 *cert = X509_new();
|
|
+ TPM2_PARTIAL_CERT *cert = TPM2_PARTIAL_CERT_new();
|
|
if (!cert) {
|
|
- LOG_ERR("X509_new");
|
|
- goto out_err;
|
|
- }
|
|
-
|
|
- X509_NAME *issuer = X509_get_issuer_name(cert);
|
|
- if (!issuer) {
|
|
- LOG_ERR("X509_get_issuer_name");
|
|
+ LOG_ERR("TPM2_PARTIAL_CERT_new");
|
|
goto out_err;
|
|
}
|
|
|
|
- int fields_added = populate_fields(issuer, ctx.issuer);
|
|
+ /* populate issuer */
|
|
+ int fields_added = populate_fields(cert->issuer, ctx.issuer);
|
|
if (fields_added <= 0) {
|
|
LOG_ERR("Could not parse any issuer fields");
|
|
goto out_err;
|
|
@@ -248,28 +211,18 @@ static tool_rc generate_partial_X509() {
|
|
LOG_INFO("Added %d issuer fields", fields_added);
|
|
}
|
|
|
|
- int ret = X509_set_issuer_name(cert, issuer); // add issuer
|
|
- if (ret != 1) {
|
|
- LOG_ERR("X509_set_issuer_name");
|
|
- goto out_err;
|
|
- }
|
|
-
|
|
+ /* populate validity */
|
|
unsigned int valid_days;
|
|
if (!tpm2_util_string_to_uint32(ctx.valid_str, &valid_days)) {
|
|
LOG_ERR("string_to_uint32");
|
|
goto out_err;
|
|
}
|
|
|
|
- X509_gmtime_adj(X509_getm_notBefore(cert), 0); // add valid not before
|
|
- X509_gmtime_adj(X509_getm_notAfter(cert), valid_days * 86400); // add valid not after
|
|
-
|
|
- X509_NAME *subject = X509_get_subject_name(cert);
|
|
- if (!subject) {
|
|
- LOG_ERR("X509_get_subject_name");
|
|
- goto out_err;
|
|
- }
|
|
+ X509_gmtime_adj(cert->validity->notBefore, 0); // add valid not before
|
|
+ X509_gmtime_adj(cert->validity->notAfter, valid_days * 86400); // add valid not after
|
|
|
|
- fields_added = populate_fields(subject, ctx.subject);
|
|
+ /* populate subject */
|
|
+ fields_added = populate_fields(cert->subject, ctx.subject);
|
|
if (fields_added <= 0) {
|
|
LOG_ERR("Could not parse any subject fields");
|
|
goto out_err;
|
|
@@ -277,51 +230,37 @@ static tool_rc generate_partial_X509() {
|
|
LOG_INFO("Added %d subject fields", fields_added);
|
|
}
|
|
|
|
- ret = X509_set_subject_name(cert, subject); // add subject
|
|
- if (ret != 1) {
|
|
- LOG_ERR("X509_NAME_add_entry_by_txt");
|
|
- goto out_err;
|
|
- }
|
|
-
|
|
+ /* populate extensions */
|
|
extv3 = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage,
|
|
- "critical,digitalSignature,keyCertSign,cRLSign");
|
|
+ "critical,digitalSignature,keyCertSign,cRLSign");
|
|
if (!extv3) {
|
|
LOG_ERR("X509V3_EXT_conf_nid");
|
|
goto out_err;
|
|
}
|
|
|
|
- ret = X509_add_ext(cert, extv3, -1); // add required v3 extention: key usage
|
|
+ int ret = TPM2_add_ext(cert, extv3, -1); // add required v3 extention: key usage
|
|
if (ret != 1) {
|
|
LOG_ERR("X509_add_ext");
|
|
goto out_err;
|
|
}
|
|
|
|
- ret = i2d_X509_bio(cert_out, cert); // print cert in DER format
|
|
+ /* output */
|
|
+ ret = i2d_TPM2_PARTIAL_CERT_bio(cert_out, cert); // print cert in DER format
|
|
if (ret != 1) {
|
|
LOG_ERR("i2d_X509_bio");
|
|
goto out_err;
|
|
}
|
|
|
|
X509_EXTENSION_free(extv3);
|
|
- X509_free(cert);
|
|
+ TPM2_PARTIAL_CERT_free(cert);
|
|
BIO_free_all(cert_out);
|
|
|
|
- ret = fixup_cert(ctx.out_path);
|
|
- if (ret) {
|
|
- LOG_ERR("fixup_cert");
|
|
- return tool_rc_general_error;
|
|
- }
|
|
-
|
|
return tool_rc_success;
|
|
|
|
out_err:
|
|
BIO_free_all(cert_out);
|
|
- if (cert) {
|
|
- X509_free(cert);
|
|
- }
|
|
- if (extv3) {
|
|
- X509_EXTENSION_free(extv3);
|
|
- }
|
|
+ X509_EXTENSION_free(extv3);
|
|
+ TPM2_PARTIAL_CERT_free(cert);
|
|
|
|
return tool_rc_general_error;
|
|
}
|
|
--
|
|
2.31.1
|
|
|