Skip to content

Commit

Permalink
Merge pull request #27 from nqminds/feat/crypto-allow-setting-absolut…
Browse files Browse the repository at this point in the history
…e-not_after

Allow setting an absolute value for the "Not After" field in certificates
  • Loading branch information
mereacre authored Nov 27, 2023
2 parents d1625d5 + 90569d0 commit 17f76d7
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 46 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

#### 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].

* add `init_binary_array()`, which initializes a new empty `struct BinaryArray`.

#### Build
Expand All @@ -20,6 +26,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
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),
Expand Down
27 changes: 27 additions & 0 deletions src/voucher/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,35 @@ typedef void *CRYPTO_CERT;

struct crypto_cert_meta {
uint64_t serial_number;
/**
* Certificate validity "Not Before" offset.
*
* This is the number of seconds after the current time for the certificate
* to start being valid.
*/
long not_before;
/**
* Certificate validity "Not After" offset.
*
* 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:
Expand Down
36 changes: 33 additions & 3 deletions src/voucher/crypto_ossl.c
Original file line number Diff line number Diff line change
Expand Up @@ -808,9 +808,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) {
Expand Down
100 changes: 57 additions & 43 deletions tests/voucher/generate_test_certs.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@
#include "voucher/crypto.h"
#include "voucher/keyvalue.h"

const long SECONDS_IN_YEAR = 10 * 60 * 60 * 24 * 365;

// Default Root CA certificate "Not After" validity offset
const long CA_NOT_AFTER = 10 * SECONDS_IN_YEAR;
// Default Subordinate 1 CA certificate "Not After" validity offset
const long CA1_NOT_AFTER = 5 * SECONDS_IN_YEAR;
// Default Subordinate 2 CA certificate "Not After" validity offset
const long CA2_NOT_AFTER = 2 * SECONDS_IN_YEAR;
// Default end-entity certificate "Not After" validity offset
const long END_ENTITY_NOT_AFTER = 13 * SECONDS_IN_YEAR / 12; // 13 months

struct context {
/** The folder to store the certs and keys in */
const char *output_dir;
Expand Down Expand Up @@ -71,13 +82,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();
Expand All @@ -96,7 +108,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"};
Expand Down Expand Up @@ -140,7 +154,7 @@ static void generate_ldevid_ca_cert(void **state) {

struct crypto_cert_meta ldevid_ca_meta = {.serial_number = 1,
.not_before = 0,
.not_after = 1234567,
.not_after = CA_NOT_AFTER,
.issuer = NULL,
.subject = NULL,
.basic_constraints =
Expand Down Expand Up @@ -174,7 +188,7 @@ static void generate_masa_tls_certs(void **state) {

struct crypto_cert_meta masa_tls_ca_meta = {.serial_number = 1,
.not_before = 0,
.not_after = 1234567,
.not_after = CA_NOT_AFTER,
.issuer = NULL,
.subject = NULL,
.basic_constraints =
Expand Down Expand Up @@ -202,7 +216,7 @@ static void generate_masa_tls_certs(void **state) {
{
struct crypto_cert_meta masa_tls_meta = {.serial_number = 12345,
.not_before = 0,
.not_after = 1234567,
.not_after = END_ENTITY_NOT_AFTER,
.issuer = NULL,
.subject = NULL,
.basic_constraints = "CA:false"};
Expand Down Expand Up @@ -246,7 +260,7 @@ static void generate_registrar_tls_certs(void **state) {

struct crypto_cert_meta registrar_tls_ca_meta = {.serial_number = 1,
.not_before = 0,
.not_after = 1234567,
.not_after = CA_NOT_AFTER,
.issuer = NULL,
.subject = NULL,
.basic_constraints =
Expand All @@ -267,13 +281,13 @@ static void generate_registrar_tls_certs(void **state) {
&registrar_tls_ca_meta, registrar_tls_ca_key.array,
registrar_tls_ca_key.length, &registrar_tls_ca_cert.array);

struct crypto_cert_meta registrar_tls_meta = {.serial_number = 12345,
.not_before = 0,
.not_after = 1234567,
.issuer = NULL,
.subject = NULL,
.basic_constraints =
"CA:false"};
struct crypto_cert_meta registrar_tls_meta = {
.serial_number = 12345,
.not_before = 0,
.not_after = END_ENTITY_NOT_AFTER,
.issuer = NULL,
.subject = NULL,
.basic_constraints = "CA:false"};

registrar_tls_meta.issuer = init_keyvalue_list();
registrar_tls_meta.subject = init_keyvalue_list();
Expand Down Expand Up @@ -348,7 +362,7 @@ static void generate_cms_certs(void **state) {

struct crypto_cert_meta cms_ca_meta = {.serial_number = 1,
.not_before = 0,
.not_after = 1234567,
.not_after = CA_NOT_AFTER,
.issuer = NULL,
.subject = NULL,
.basic_constraints =
Expand All @@ -373,7 +387,7 @@ static void generate_cms_certs(void **state) {
{
struct crypto_cert_meta int2_cms_meta = {.serial_number = 12345,
.not_before = 0,
.not_after = 1234567,
.not_after = CA1_NOT_AFTER,
.issuer = NULL,
.subject = NULL,
.basic_constraints = "CA:false"};
Expand Down Expand Up @@ -404,7 +418,7 @@ static void generate_cms_certs(void **state) {
{
struct crypto_cert_meta int1_cms_meta = {.serial_number = 12345,
.not_before = 0,
.not_after = 1234567,
.not_after = CA2_NOT_AFTER,
.issuer = NULL,
.subject = NULL,
.basic_constraints = "CA:false"};
Expand Down Expand Up @@ -433,13 +447,13 @@ static void generate_cms_certs(void **state) {
save_cert("int1-cms", context, &int1_cms_key, &int1_cms_cert), errno);

{
struct crypto_cert_meta pledge_cms_meta = {.serial_number = 1,
.not_before = 0,
.not_after = 1234567,
.issuer = NULL,
.subject = NULL,
.basic_constraints =
"CA:false"};
struct crypto_cert_meta pledge_cms_meta = {
.serial_number = 1,
.not_before = 0,
.not_after = END_ENTITY_NOT_AFTER,
.issuer = NULL,
.subject = NULL,
.basic_constraints = "CA:false"};

pledge_cms_meta.issuer = init_keyvalue_list();
pledge_cms_meta.subject = init_keyvalue_list();
Expand Down Expand Up @@ -473,13 +487,13 @@ static void generate_cms_certs(void **state) {
}

{
struct crypto_cert_meta registrar_cms_meta = {.serial_number = 1,
.not_before = 0,
.not_after = 1234567,
.issuer = NULL,
.subject = NULL,
.basic_constraints =
"CA:false"};
struct crypto_cert_meta registrar_cms_meta = {
.serial_number = 1,
.not_before = 0,
.not_after = END_ENTITY_NOT_AFTER,
.issuer = NULL,
.subject = NULL,
.basic_constraints = "CA:false"};

registrar_cms_meta.issuer = init_keyvalue_list();
registrar_cms_meta.subject = init_keyvalue_list();
Expand Down Expand Up @@ -514,13 +528,13 @@ static void generate_cms_certs(void **state) {
}

{
struct crypto_cert_meta masa_cms_meta = {.serial_number = 1,
.not_before = 0,
.not_after = 1234567,
.issuer = NULL,
.subject = NULL,
.basic_constraints =
"CA:false"};
struct crypto_cert_meta masa_cms_meta = {
.serial_number = 1,
.not_before = 0,
.not_after = END_ENTITY_NOT_AFTER,
.issuer = NULL,
.subject = NULL,
.basic_constraints = "CA:false"};

masa_cms_meta.issuer = init_keyvalue_list();
masa_cms_meta.subject = init_keyvalue_list();
Expand Down

0 comments on commit 17f76d7

Please sign in to comment.