From 582fb6f3e9ee05db8054ae2abe0b64e4f2549410 Mon Sep 17 00:00:00 2001 From: Alois Klink Date: Fri, 16 Jun 2023 13:11:59 +0100 Subject: [PATCH] feat(crypto): add `not_after_absolute` field Add `not_after_absolute` field to `struct crypto_cert_meta`. Unlike the existing `not_after` field, which represents an offset from the current time, the `not_after_absolute` field represents an ASN.1 GENERALIZEDTIME absolute time. It can be set to `"99991231235959Z"` for a [long-lived pledge certificate][rfc8995#2.6.2]. [rfc8995#2.6.2]: https://www.rfc-editor.org/rfc/rfc8995.html#name-infinite-lifetime-of-idevid BREAKING CHANGE: This is an ABI breaking change for the voucher lib. --- CHANGELOG.md | 16 +++++++++++++ src/voucher/crypto.h | 15 ++++++++++++ src/voucher/crypto_ossl.c | 36 ++++++++++++++++++++++++++--- tests/voucher/generate_test_certs.c | 19 ++++++++------- 4 files changed, 75 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5da33ec..0de8f84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,12 +10,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * brski tool to demonstrate the Registrar and MASA functionalities +#### voucher + +* add `not_after_absolute` field to `struct crypto_cert_meta`. + Unlike the existing `not_after` field, which represents an offset from the + current time, the `not_after_absolute` field represents an absolute time. + It can be set to `"99991231235959Z"` for a + [long-lived pledge certificate][rfc8995#2.6.2]. + +[rfc8995#2.6.2]: https://www.rfc-editor.org/rfc/rfc8995.html#name-infinite-lifetime-of-idevid + #### Build * add `BUILD_JSMN` CMake option. Set this to `OFF` in case you want to use your system's [jsmn](https://github.com/zserge/jsmn) lib, instead of downloading it automatically. +### Changed + +#### voucher + +**The voucher ABI has breaking changes**. + ## [0.2.0] - 2023-03-27 ### Added * Voucher artifact implementation as per [RFC8366](https://www.rfc-editor.org/info/rfc8366), diff --git a/src/voucher/crypto.h b/src/voucher/crypto.h index 17e9cd0..ce81f8e 100644 --- a/src/voucher/crypto.h +++ b/src/voucher/crypto.h @@ -36,8 +36,23 @@ struct crypto_cert_meta { * * This is the number of seconds after the current for the certificate to * stop being valid (aka expire). + * + * Either this or #not_after_absolute must be set (not both). */ long not_after; + /** + * Optional Certificate validity "Not After" string. + * + * This must be an ASN.1 GENERALIZEDTIME string, e.g. in format + * `YYYYMMDDHH[MM[SS[.fff]]]Z`. + * + * Either this or #not_after must be set (not both). + + * Set to `"99991231235959Z"` for a [long-lived pledge certificate][1] + * [1]: + https://www.rfc-editor.org/rfc/rfc8995.html#name-infinite-lifetime-of-idevid + */ + const char *not_after_absolute; /* Decoded key/value pairs: diff --git a/src/voucher/crypto_ossl.c b/src/voucher/crypto_ossl.c index a03e0ab..7b56e9c 100644 --- a/src/voucher/crypto_ossl.c +++ b/src/voucher/crypto_ossl.c @@ -780,9 +780,39 @@ static int set_certificate_meta(X509 *x509, return -1; } - if (X509_gmtime_adj(X509_getm_notAfter(x509), meta->not_after) == NULL) { - log_error("X509_gmtime_adj fail"); - return -1; + if (meta->not_after_absolute) { + if (meta->not_after) { + log_error("Only not_after_absolute or not_after should be set."); + return -1; + } + ASN1_TIME *notAfter = ASN1_TIME_set(NULL, 0); + if (ASN1_TIME_set_string(notAfter, meta->not_after_absolute) != 1) { + log_error("ASN1_TIME_set_string failed to set string %s", + meta->not_after_absolute); + ASN1_STRING_free(notAfter); + return -1; + } + + if (ASN1_TIME_normalize(notAfter) != 1) { + log_error("ASN1_TIME_normalize failed to normalize string %s", + meta->not_after_absolute); + ASN1_STRING_free(notAfter); + return -1; + } + + if (X509_set1_notAfter(x509, notAfter) != 1) { + log_error("X509_set1_notAfter failed to set string %s", + meta->not_after_absolute); + ASN1_STRING_free(notAfter); + return -1; + } + + ASN1_STRING_free(notAfter); + } else { + if (X509_gmtime_adj(X509_getm_notAfter(x509), meta->not_after) == NULL) { + log_error("X509_gmtime_adj fail"); + return -1; + } } if (meta->issuer != NULL) { diff --git a/tests/voucher/generate_test_certs.c b/tests/voucher/generate_test_certs.c index eece491..b9d7f68 100644 --- a/tests/voucher/generate_test_certs.c +++ b/tests/voucher/generate_test_certs.c @@ -71,13 +71,14 @@ static void generate_idevid_certs(void **state) { // Generate ROOT CA for MASA idevid_ca_key.length = crypto_generate_eckey(&idevid_ca_key.array); - struct crypto_cert_meta idevid_ca_meta = {.serial_number = 1, - .not_before = 0, - .not_after = 1234567, - .issuer = NULL, - .subject = NULL, - .basic_constraints = - "critical,CA:TRUE"}; + struct crypto_cert_meta idevid_ca_meta = { + .serial_number = 1, + .not_before = 0, + // Long-lived pledge CA cert + .not_after_absolute = "99991231235959Z", + .issuer = NULL, + .subject = NULL, + .basic_constraints = "critical,CA:TRUE"}; idevid_ca_meta.issuer = init_keyvalue_list(); idevid_ca_meta.subject = init_keyvalue_list(); @@ -96,7 +97,9 @@ static void generate_idevid_certs(void **state) { { struct crypto_cert_meta idev_meta = {.serial_number = 12345, .not_before = 0, - .not_after = 1234567, + // Long-lived pledge certificate + .not_after_absolute = + "99991231235959Z", .issuer = NULL, .subject = NULL, .basic_constraints = "CA:false"};