From 70b17e5a00dae537181e2722033f190cc1550139 Mon Sep 17 00:00:00 2001 From: "Jonathan M. Wilbur" Date: Mon, 16 Sep 2024 22:50:14 +0000 Subject: [PATCH] feat: support the timeSpecification X.509v3 extension Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/25476) --- crypto/x509/build.info | 2 +- crypto/x509/ext_dat.h | 1 + crypto/x509/standard_exts.h | 1 + crypto/x509/v3_timespec.c | 598 ++++++++++++++++++++++++++++++++++++ include/openssl/x509v3.h.in | 186 +++++++++++ 5 files changed, 787 insertions(+), 1 deletion(-) create mode 100644 crypto/x509/v3_timespec.c diff --git a/crypto/x509/build.info b/crypto/x509/build.info index 3441f49016..62e701dd5e 100644 --- a/crypto/x509/build.info +++ b/crypto/x509/build.info @@ -18,7 +18,7 @@ SOURCE[../../libcrypto]=\ v3_soa_id.c v3_no_ass.c v3_group_ac.c v3_single_use.c v3_ind_iss.c \ x509_acert.c x509aset.c t_acert.c x_ietfatt.c v3_ac_tgt.c v3_sda.c \ v3_usernotice.c v3_battcons.c v3_audit_id.c v3_iobo.c v3_authattid.c \ - v3_rolespec.c v3_attrdesc.c + v3_rolespec.c v3_attrdesc.c v3_timespec.c IF[{- !$disabled{'deprecated-3.0'} -}] SOURCE[../../libcrypto]=x509type.c diff --git a/crypto/x509/ext_dat.h b/crypto/x509/ext_dat.h index 24f381e0ce..efe8abb104 100644 --- a/crypto/x509/ext_dat.h +++ b/crypto/x509/ext_dat.h @@ -45,3 +45,4 @@ extern const X509V3_EXT_METHOD ossl_v3_issued_on_behalf_of; extern const X509V3_EXT_METHOD ossl_v3_authority_attribute_identifier; extern const X509V3_EXT_METHOD ossl_v3_role_spec_cert_identifier; extern const X509V3_EXT_METHOD ossl_v3_attribute_descriptor; +extern const X509V3_EXT_METHOD ossl_v3_time_specification; diff --git a/crypto/x509/standard_exts.h b/crypto/x509/standard_exts.h index 482d4e6256..4ed059bd61 100644 --- a/crypto/x509/standard_exts.h +++ b/crypto/x509/standard_exts.h @@ -80,6 +80,7 @@ static const X509V3_EXT_METHOD *standard_exts[] = { &ossl_v3_role_spec_cert_identifier, &ossl_v3_battcons, &ossl_v3_delegated_name_constraints, + &ossl_v3_time_specification, &ossl_v3_attribute_descriptor, &ossl_v3_user_notice, &ossl_v3_soa_identifier, diff --git a/crypto/x509/v3_timespec.c b/crypto/x509/v3_timespec.c new file mode 100644 index 0000000000..30f6590826 --- /dev/null +++ b/crypto/x509/v3_timespec.c @@ -0,0 +1,598 @@ +/* + * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include +#include "ext_dat.h" + +static const char *WEEKDAY_NAMES[7] = { + "SUN", + "MON", + "TUE", + "WED", + "THU", + "FRI", + "SAT" +}; + +static const char *WEEK_NAMES[5] = { + "first", + "second", + "third", + "fourth", + "final" +}; + +static const char *MONTH_NAMES[12] = { + "JAN", + "FEB", + "MAR", + "APR", + "MAY", + "JUN", + "JUL", + "AUG", + "SEPT", + "OCT", + "NOV", + "DEC" +}; + +ASN1_SEQUENCE(OSSL_TIME_SPEC_ABSOLUTE) = { + ASN1_EXP_OPT(OSSL_TIME_SPEC_ABSOLUTE, startTime, ASN1_GENERALIZEDTIME, 0), + ASN1_EXP_OPT(OSSL_TIME_SPEC_ABSOLUTE, endTime, ASN1_GENERALIZEDTIME, 1), +} ASN1_SEQUENCE_END(OSSL_TIME_SPEC_ABSOLUTE) + +ASN1_SEQUENCE(OSSL_DAY_TIME) = { + ASN1_EXP_OPT(OSSL_DAY_TIME, hour, ASN1_INTEGER, 0), + ASN1_EXP_OPT(OSSL_DAY_TIME, minute, ASN1_INTEGER, 1), + ASN1_EXP_OPT(OSSL_DAY_TIME, second, ASN1_INTEGER, 2), +} ASN1_SEQUENCE_END(OSSL_DAY_TIME) + +ASN1_SEQUENCE(OSSL_DAY_TIME_BAND) = { + ASN1_EXP_OPT(OSSL_DAY_TIME_BAND, startDayTime, OSSL_DAY_TIME, 0), + ASN1_EXP_OPT(OSSL_DAY_TIME_BAND, endDayTime, OSSL_DAY_TIME, 1), +} ASN1_SEQUENCE_END(OSSL_DAY_TIME_BAND) + +ASN1_CHOICE(OSSL_NAMED_DAY) = { + ASN1_SET_OF(OSSL_NAMED_DAY, choice.intNamedDays, ASN1_ENUMERATED), + ASN1_SIMPLE(OSSL_NAMED_DAY, choice.bitNamedDays, ASN1_BIT_STRING), +} ASN1_CHOICE_END(OSSL_NAMED_DAY) + +ASN1_CHOICE(OSSL_TIME_SPEC_X_DAY_OF) = { + ASN1_EXP(OSSL_TIME_SPEC_X_DAY_OF, choice.first, OSSL_NAMED_DAY, 1), + ASN1_EXP(OSSL_TIME_SPEC_X_DAY_OF, choice.second, OSSL_NAMED_DAY, 2), + ASN1_EXP(OSSL_TIME_SPEC_X_DAY_OF, choice.third, OSSL_NAMED_DAY, 3), + ASN1_EXP(OSSL_TIME_SPEC_X_DAY_OF, choice.fourth, OSSL_NAMED_DAY, 4), + ASN1_EXP(OSSL_TIME_SPEC_X_DAY_OF, choice.fifth, OSSL_NAMED_DAY, 5), +} ASN1_CHOICE_END(OSSL_TIME_SPEC_X_DAY_OF) + +ASN1_CHOICE(OSSL_TIME_SPEC_DAY) = { + ASN1_SET_OF(OSSL_TIME_SPEC_DAY, choice.intDay, ASN1_INTEGER), + ASN1_SIMPLE(OSSL_TIME_SPEC_DAY, choice.bitDay, ASN1_BIT_STRING), + ASN1_SIMPLE(OSSL_TIME_SPEC_DAY, choice.dayOf, OSSL_TIME_SPEC_X_DAY_OF), +} ASN1_CHOICE_END(OSSL_TIME_SPEC_DAY) + +ASN1_CHOICE(OSSL_TIME_SPEC_WEEKS) = { + ASN1_SIMPLE(OSSL_TIME_SPEC_WEEKS, choice.allWeeks, ASN1_NULL), + ASN1_SET_OF(OSSL_TIME_SPEC_WEEKS, choice.intWeek, ASN1_INTEGER), + ASN1_SIMPLE(OSSL_TIME_SPEC_WEEKS, choice.bitWeek, ASN1_BIT_STRING), +} ASN1_CHOICE_END(OSSL_TIME_SPEC_WEEKS) + +ASN1_CHOICE(OSSL_TIME_SPEC_MONTH) = { + ASN1_SIMPLE(OSSL_TIME_SPEC_MONTH, choice.allMonths, ASN1_NULL), + ASN1_SET_OF(OSSL_TIME_SPEC_MONTH, choice.intMonth, ASN1_INTEGER), + ASN1_SIMPLE(OSSL_TIME_SPEC_MONTH, choice.bitMonth, ASN1_BIT_STRING), +} ASN1_CHOICE_END(OSSL_TIME_SPEC_MONTH) + +ASN1_SEQUENCE(OSSL_TIME_PERIOD) = { + ASN1_EXP_SET_OF_OPT(OSSL_TIME_PERIOD, timesOfDay, OSSL_DAY_TIME_BAND, 0), + ASN1_EXP_OPT(OSSL_TIME_PERIOD, days, OSSL_TIME_SPEC_DAY, 1), + ASN1_EXP_OPT(OSSL_TIME_PERIOD, weeks, OSSL_TIME_SPEC_WEEKS, 2), + ASN1_EXP_OPT(OSSL_TIME_PERIOD, months, OSSL_TIME_SPEC_MONTH, 3), + ASN1_EXP_SET_OF_OPT(OSSL_TIME_PERIOD, years, ASN1_INTEGER, 4), +} ASN1_SEQUENCE_END(OSSL_TIME_PERIOD) + +ASN1_CHOICE(OSSL_TIME_SPEC_TIME) = { + ASN1_SIMPLE(OSSL_TIME_SPEC_TIME, choice.absolute, OSSL_TIME_SPEC_ABSOLUTE), + ASN1_SET_OF(OSSL_TIME_SPEC_TIME, choice.periodic, OSSL_TIME_PERIOD) +} ASN1_CHOICE_END(OSSL_TIME_SPEC_TIME) + +ASN1_SEQUENCE(OSSL_TIME_SPEC) = { + ASN1_SIMPLE(OSSL_TIME_SPEC, time, OSSL_TIME_SPEC_TIME), + ASN1_OPT(OSSL_TIME_SPEC, notThisTime, ASN1_FBOOLEAN), + ASN1_OPT(OSSL_TIME_SPEC, timeZone, ASN1_INTEGER), +} ASN1_SEQUENCE_END(OSSL_TIME_SPEC) + +IMPLEMENT_ASN1_FUNCTIONS(OSSL_DAY_TIME) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_DAY_TIME_BAND) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_TIME_SPEC_DAY) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_TIME_SPEC_WEEKS) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_TIME_SPEC_MONTH) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_NAMED_DAY) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_TIME_SPEC_X_DAY_OF) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_TIME_SPEC_ABSOLUTE) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_TIME_SPEC_TIME) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_TIME_SPEC) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_TIME_PERIOD) + +static int i2r_OSSL_TIME_SPEC_ABSOLUTE(X509V3_EXT_METHOD *method, + OSSL_TIME_SPEC_ABSOLUTE *time, + BIO *out, int indent) +{ + if (time->startTime != NULL && time->endTime != NULL) { + if (!BIO_puts(out, "Any time between ")) + return 0; + if (!ossl_asn1_time_print_ex(out, time->startTime, 0)) + return 0; + if (!BIO_puts(out, " and ")) + return 0; + if (!ossl_asn1_time_print_ex(out, time->endTime, 0)) + return 0; + } else if (time->startTime != NULL) { + if (!BIO_puts(out, "Any time after ")) + return 0; + if (!ossl_asn1_time_print_ex(out, time->startTime, 0)) + return 0; + if (BIO_printf(out, "%.*s", time->startTime->length, time->startTime->data) <= 0) + return 0; + } else if (time->endTime != NULL) { + if (!BIO_puts(out, "Any time until ")) + return 0; + if (!ossl_asn1_time_print_ex(out, time->endTime, 0)) + return 0; + } else { /* Invalid: there must be SOME time specified. */ + return BIO_puts(out, "INVALID (EMPTY)"); + } + return 1; +} + +static int i2r_OSSL_DAY_TIME(X509V3_EXT_METHOD *method, + OSSL_DAY_TIME *dt, + BIO *out, int indent) +{ + int64_t h = 0; + int64_t m = 0; + int64_t s = 0; + + if (!dt->hour || !ASN1_INTEGER_get_int64(&h, dt->hour)) + return 0; + if (dt->minute && !ASN1_INTEGER_get_int64(&m, dt->minute)) + return 0; + if (dt->minute && !ASN1_INTEGER_get_int64(&s, dt->second)) + return 0; + return BIO_printf(out, "%02lld:%02lld:%02lld", + (long long int)h, (long long int)m, (long long int)s) > 0; +} + +static int i2r_OSSL_DAY_TIME_BAND(X509V3_EXT_METHOD *method, + OSSL_DAY_TIME_BAND *band, + BIO *out, int indent) +{ + if (band->startDayTime) { + if (!i2r_OSSL_DAY_TIME(method, band->startDayTime, out, indent)) + return 0; + } else if (!BIO_puts(out, "00:00:00")) { + return 0; + } + if (!BIO_puts(out, " - ")) + return 0; + if (band->endDayTime) { + if (!i2r_OSSL_DAY_TIME(method, band->endDayTime, out, indent)) + return 0; + } else if (!BIO_puts(out, "23:59:59")) { + return 0; + } + return 1; +} + +static int print_int_month(BIO *out, int64_t month) +{ + switch (month) { + case (OSSL_TIME_SPEC_INT_MONTH_JAN): + return BIO_puts(out, "JAN"); + case (OSSL_TIME_SPEC_INT_MONTH_FEB): + return BIO_puts(out, "FEB"); + case (OSSL_TIME_SPEC_INT_MONTH_MAR): + return BIO_puts(out, "MAR"); + case (OSSL_TIME_SPEC_INT_MONTH_APR): + return BIO_puts(out, "APR"); + case (OSSL_TIME_SPEC_INT_MONTH_MAY): + return BIO_puts(out, "MAY"); + case (OSSL_TIME_SPEC_INT_MONTH_JUN): + return BIO_puts(out, "JUN"); + case (OSSL_TIME_SPEC_INT_MONTH_JUL): + return BIO_puts(out, "JUL"); + case (OSSL_TIME_SPEC_INT_MONTH_AUG): + return BIO_puts(out, "AUG"); + case (OSSL_TIME_SPEC_INT_MONTH_SEP): + return BIO_puts(out, "SEP"); + case (OSSL_TIME_SPEC_INT_MONTH_OCT): + return BIO_puts(out, "OCT"); + case (OSSL_TIME_SPEC_INT_MONTH_NOV): + return BIO_puts(out, "NOV"); + case (OSSL_TIME_SPEC_INT_MONTH_DEC): + return BIO_puts(out, "DEC"); + default: + return 0; + } + return 0; +} + +static int print_bit_month(BIO *out, ASN1_BIT_STRING *bs) +{ + int i = OSSL_TIME_SPEC_BIT_MONTH_JAN; + int j = 0; + + for (; i <= OSSL_TIME_SPEC_BIT_MONTH_DEC; i++) { + if (ASN1_BIT_STRING_get_bit(bs, i)) { + if (j > 0 && !BIO_puts(out, ", ")) + return 0; + j++; + if (!BIO_puts(out, MONTH_NAMES[i])) + return 0; + } + } + return 1; +} + +/* + * It might seem like you could just print the bits of the string numerically, + * but the fifth bit has the special meaning of "the final week" imputed to it + * by the text of ITU-T Recommendation X.520. + */ +static int print_bit_week(BIO *out, ASN1_BIT_STRING *bs) +{ + int i = OSSL_TIME_SPEC_BIT_WEEKS_1; + int j = 0; + + for (; i <= OSSL_TIME_SPEC_BIT_WEEKS_5; i++) { + if (ASN1_BIT_STRING_get_bit(bs, i)) { + if (j > 0 && !BIO_puts(out, ", ")) + return 0; + j++; + if (!BIO_puts(out, WEEK_NAMES[i])) + return 0; + } + } + return 1; +} + +static int print_day_of_week(BIO *out, ASN1_BIT_STRING *bs) +{ + int i = OSSL_TIME_SPEC_DAY_BIT_SUN; + int j = 0; + + for (; i <= OSSL_TIME_SPEC_DAY_BIT_SAT; i++) { + if (ASN1_BIT_STRING_get_bit(bs, i)) { + if (j > 0 && !BIO_puts(out, ", ")) + return 0; + j++; + if (!BIO_puts(out, WEEKDAY_NAMES[i])) + return 0; + } + } + return 1; +} + +static int print_int_day_of_week(BIO *out, int64_t dow) +{ + switch (dow) { + case (OSSL_TIME_SPEC_DAY_INT_SUN): + return BIO_puts(out, "SUN"); + case (OSSL_TIME_SPEC_DAY_INT_MON): + return BIO_puts(out, "MON"); + case (OSSL_TIME_SPEC_DAY_INT_TUE): + return BIO_puts(out, "TUE"); + case (OSSL_TIME_SPEC_DAY_INT_WED): + return BIO_puts(out, "WED"); + case (OSSL_TIME_SPEC_DAY_INT_THU): + return BIO_puts(out, "THU"); + case (OSSL_TIME_SPEC_DAY_INT_FRI): + return BIO_puts(out, "FRI"); + case (OSSL_TIME_SPEC_DAY_INT_SAT): + return BIO_puts(out, "SAT"); + default: + return 0; + } + return 0; +} + +static int print_int_named_day(BIO *out, int64_t nd) +{ + switch (nd) { + case (OSSL_NAMED_DAY_INT_SUN): + return BIO_puts(out, "SUN"); + case (OSSL_NAMED_DAY_INT_MON): + return BIO_puts(out, "MON"); + case (OSSL_NAMED_DAY_INT_TUE): + return BIO_puts(out, "TUE"); + case (OSSL_NAMED_DAY_INT_WED): + return BIO_puts(out, "WED"); + case (OSSL_NAMED_DAY_INT_THU): + return BIO_puts(out, "THU"); + case (OSSL_NAMED_DAY_INT_FRI): + return BIO_puts(out, "FRI"); + case (OSSL_NAMED_DAY_INT_SAT): + return BIO_puts(out, "SAT"); + default: + return 0; + } + return 0; +} + +static int print_bit_named_day(BIO *out, ASN1_BIT_STRING *bs) +{ + return print_day_of_week(out, bs); +} + +static int i2r_OSSL_PERIOD(X509V3_EXT_METHOD *method, + OSSL_TIME_PERIOD *p, + BIO *out, int indent) +{ + int i; + OSSL_DAY_TIME_BAND *band; + ASN1_INTEGER *big_val; + int64_t small_val; + OSSL_NAMED_DAY *nd; + + if (BIO_printf(out, "%*sPeriod:\n", indent, "") <= 0) + return 0; + if (p->timesOfDay) { + if (BIO_printf(out, "%*sDaytime bands:\n", indent + 4, "") <= 0) + return 0; + for (i = 0; i < sk_OSSL_DAY_TIME_BAND_num(p->timesOfDay); i++) { + band = sk_OSSL_DAY_TIME_BAND_value(p->timesOfDay, i); + if (BIO_printf(out, "%*s", indent + 8, "") <= 0) + return 0; + if (!i2r_OSSL_DAY_TIME_BAND(method, band, out, indent + 8)) + return 0; + if (!BIO_puts(out, "\n")) + return 0; + } + } + if (p->days) { + if (p->days->type == OSSL_TIME_SPEC_DAY_TYPE_INT) { + if (p->weeks != NULL) { + if (BIO_printf(out, "%*sDays of the week: ", indent + 4, "") <= 0) + return 0; + } else if (p->months != NULL) { + if (BIO_printf(out, "%*sDays of the month: ", indent + 4, "") <= 0) + return 0; + } else if (p->years != NULL) { + if (BIO_printf(out, "%*sDays of the year: ", indent + 4, "") <= 0) + return 0; + } + } else { + if (BIO_printf(out, "%*sDays: ", indent + 4, "") <= 0) + return 0; + } + + switch (p->days->type) { + case (OSSL_TIME_SPEC_DAY_TYPE_INT): + for (i = 0; i < sk_ASN1_INTEGER_num(p->days->choice.intDay); i++) { + big_val = sk_ASN1_INTEGER_value(p->days->choice.intDay, i); + if (!ASN1_INTEGER_get_int64(&small_val, big_val)) + return 0; + if (i > 0 && !BIO_puts(out, ", ")) + return 0; + /* If weeks is defined, then print day of week by name. */ + if (p->weeks != NULL) { + if (!print_int_day_of_week(out, small_val)) + return 0; + } else if (BIO_printf(out, "%lld", (long long int)small_val) <= 0) { + return 0; + } + } + break; + case (OSSL_TIME_SPEC_DAY_TYPE_BIT): + if (!print_day_of_week(out, p->days->choice.bitDay)) + return 0; + break; + case (OSSL_TIME_SPEC_DAY_TYPE_DAY_OF): + switch (p->days->choice.dayOf->type) { + case (OSSL_TIME_SPEC_X_DAY_OF_FIRST): + if (!BIO_puts(out, "FIRST ")) + return 0; + nd = p->days->choice.dayOf->choice.first; + break; + case (OSSL_TIME_SPEC_X_DAY_OF_SECOND): + if (!BIO_puts(out, "SECOND ")) + return 0; + nd = p->days->choice.dayOf->choice.second; + break; + case (OSSL_TIME_SPEC_X_DAY_OF_THIRD): + if (!BIO_puts(out, "THIRD ")) + return 0; + nd = p->days->choice.dayOf->choice.third; + break; + case (OSSL_TIME_SPEC_X_DAY_OF_FOURTH): + if (!BIO_puts(out, "FOURTH ")) + return 0; + nd = p->days->choice.dayOf->choice.fourth; + break; + case (OSSL_TIME_SPEC_X_DAY_OF_FIFTH): + if (!BIO_puts(out, "FIFTH ")) + return 0; + nd = p->days->choice.dayOf->choice.fifth; + break; + default: + return 0; + } + switch (nd->type) { + case (OSSL_NAMED_DAY_TYPE_INT): + if (!ASN1_INTEGER_get_int64(&small_val, nd->choice.intNamedDays)) + return 0; + if (!print_int_named_day(out, small_val)) + return 0; + break; + case (OSSL_NAMED_DAY_TYPE_BIT): + if (!print_bit_named_day(out, nd->choice.bitNamedDays)) + return 0; + break; + default: + return 0; + } + break; + default: + return 0; + } + if (!BIO_puts(out, "\n")) + return 0; + } + if (p->weeks) { + if (p->weeks->type == OSSL_TIME_SPEC_WEEKS_TYPE_INT) { + if (p->months != NULL) { + if (BIO_printf(out, "%*sWeeks of the month: ", indent + 4, "") <= 0) + return 0; + } else if (p->years != NULL) { + if (BIO_printf(out, "%*sWeeks of the year: ", indent + 4, "") <= 0) + return 0; + } + } else { + if (BIO_printf(out, "%*sWeeks: ", indent + 4, "") <= 0) + return 0; + } + + switch (p->weeks->type) { + case (OSSL_TIME_SPEC_WEEKS_TYPE_ALL): + if (!BIO_puts(out, "ALL")) + return 0; + break; + case (OSSL_TIME_SPEC_WEEKS_TYPE_INT): + for (i = 0; i < sk_ASN1_INTEGER_num(p->weeks->choice.intWeek); i++) { + big_val = sk_ASN1_INTEGER_value(p->weeks->choice.intWeek, i); + if (!ASN1_INTEGER_get_int64(&small_val, big_val)) + return 0; + if (i > 0 && !BIO_puts(out, ", ")) + return 0; + if (!BIO_printf(out, "%lld", (long long int)small_val)) + return 0; + } + break; + case (OSSL_TIME_SPEC_WEEKS_TYPE_BIT): + if (!print_bit_week(out, p->weeks->choice.bitWeek)) + return 0; + break; + default: + return 0; + } + if (!BIO_puts(out, "\n")) + return 0; + } + if (p->months) { + if (BIO_printf(out, "%*sMonths: ", indent + 4, "") <= 0) + return 0; + switch (p->months->type) { + case (OSSL_TIME_SPEC_MONTH_TYPE_ALL): + if (!BIO_puts(out, "ALL")) + return 0; + break; + case (OSSL_TIME_SPEC_MONTH_TYPE_INT): + for (i = 0; i < sk_ASN1_INTEGER_num(p->months->choice.intMonth); i++) { + big_val = sk_ASN1_INTEGER_value(p->months->choice.intMonth, i); + if (!ASN1_INTEGER_get_int64(&small_val, big_val)) + return 0; + if (i > 0 && !BIO_puts(out, ", ")) + return 0; + if (!print_int_month(out, small_val)) + return 0; + } + break; + case (OSSL_TIME_SPEC_MONTH_TYPE_BIT): + if (!print_bit_month(out, p->months->choice.bitMonth)) + return 0; + break; + default: + return 0; + } + if (!BIO_puts(out, "\n")) + return 0; + } + if (p->years) { + if (BIO_printf(out, "%*sYears: ", indent + 4, "") <= 0) + return 0; + for (i = 0; i < sk_ASN1_INTEGER_num(p->years); i++) { + big_val = sk_ASN1_INTEGER_value(p->years, i); + if (!ASN1_INTEGER_get_int64(&small_val, big_val)) + return 0; + if (i > 0 && !BIO_puts(out, ", ")) + return 0; + if (BIO_printf(out, "%04lld", (long long int)small_val) <= 0) + return 0; + } + } + return 1; +} + +static int i2r_OSSL_TIME_SPEC_TIME(X509V3_EXT_METHOD *method, + OSSL_TIME_SPEC_TIME *time, + BIO *out, int indent) +{ + OSSL_TIME_PERIOD *tp; + int i; + + switch (time->type) { + case (OSSL_TIME_SPEC_TIME_TYPE_ABSOLUTE): + if (BIO_printf(out, "%*sAbsolute: ", indent, "") <= 0) + return 0; + if (i2r_OSSL_TIME_SPEC_ABSOLUTE(method, time->choice.absolute, out, indent + 4) <= 0) + return 0; + return BIO_puts(out, "\n"); + case (OSSL_TIME_SPEC_TIME_TYPE_PERIODIC): + if (BIO_printf(out, "%*sPeriodic:\n", indent, "") <= 0) + return 0; + for (i = 0; i < sk_OSSL_TIME_PERIOD_num(time->choice.periodic); i++) { + if (i > 0 && !BIO_puts(out, "\n")) + return 0; + tp = sk_OSSL_TIME_PERIOD_value(time->choice.periodic, i); + if (!i2r_OSSL_PERIOD(method, tp, out, indent + 4)) + return 0; + } + return BIO_puts(out, "\n"); + default: + return 0; + } + return 0; +} + +static int i2r_OSSL_TIME_SPEC(X509V3_EXT_METHOD *method, + OSSL_TIME_SPEC *time, + BIO *out, int indent) +{ + int64_t tz; + + if (time->timeZone) { + if (ASN1_INTEGER_get_int64(&tz, time->timeZone) != 1) + return 0; + if (BIO_printf(out, "%*sTimezone: UTC%+03lld:00\n", indent, "", (long long int)tz) <= 0) + return 0; + } + if (time->notThisTime > 0) { + if (BIO_printf(out, "%*sNOT this time:\n", indent, "") <= 0) + return 0; + } else if (BIO_printf(out, "%*sTime:\n", indent, "") <= 0) { + return 0; + } + return i2r_OSSL_TIME_SPEC_TIME(method, time->time, out, indent + 4); +} + +const X509V3_EXT_METHOD ossl_v3_time_specification = { + NID_time_specification, X509V3_EXT_MULTILINE, + ASN1_ITEM_ref(OSSL_TIME_SPEC), + 0, 0, 0, 0, + 0, 0, + 0, + 0, + (X509V3_EXT_I2R)i2r_OSSL_TIME_SPEC, + NULL, + NULL +}; diff --git a/include/openssl/x509v3.h.in b/include/openssl/x509v3.h.in index 6bd5792c92..557054c630 100644 --- a/include/openssl/x509v3.h.in +++ b/include/openssl/x509v3.h.in @@ -1045,6 +1045,7 @@ typedef struct OSSL_ROLE_SPEC_CERT_ID_st { } OSSL_ROLE_SPEC_CERT_ID; DECLARE_ASN1_FUNCTIONS(OSSL_ROLE_SPEC_CERT_ID) + {- generate_stack_macros("OSSL_ROLE_SPEC_CERT_ID"); -} @@ -1092,6 +1093,191 @@ DECLARE_ASN1_FUNCTIONS(OSSL_INFO_SYNTAX_POINTER) DECLARE_ASN1_FUNCTIONS(OSSL_PRIVILEGE_POLICY_ID) DECLARE_ASN1_FUNCTIONS(OSSL_ATTRIBUTE_DESCRIPTOR) +typedef struct OSSL_TIME_SPEC_ABSOLUTE_st { + ASN1_GENERALIZEDTIME *startTime; + ASN1_GENERALIZEDTIME *endTime; +} OSSL_TIME_SPEC_ABSOLUTE; + +typedef struct OSSL_DAY_TIME_st { + ASN1_INTEGER *hour; + ASN1_INTEGER *minute; + ASN1_INTEGER *second; +} OSSL_DAY_TIME; + +typedef struct OSSL_DAY_TIME_BAND_st { + OSSL_DAY_TIME *startDayTime; + OSSL_DAY_TIME *endDayTime; +} OSSL_DAY_TIME_BAND; + +# define OSSL_NAMED_DAY_TYPE_INT 0 +# define OSSL_NAMED_DAY_TYPE_BIT 1 +# define OSSL_NAMED_DAY_INT_SUN 1 +# define OSSL_NAMED_DAY_INT_MON 2 +# define OSSL_NAMED_DAY_INT_TUE 3 +# define OSSL_NAMED_DAY_INT_WED 4 +# define OSSL_NAMED_DAY_INT_THU 5 +# define OSSL_NAMED_DAY_INT_FRI 6 +# define OSSL_NAMED_DAY_INT_SAT 7 +# define OSSL_NAMED_DAY_BIT_SUN 0 +# define OSSL_NAMED_DAY_BIT_MON 1 +# define OSSL_NAMED_DAY_BIT_TUE 2 +# define OSSL_NAMED_DAY_BIT_WED 3 +# define OSSL_NAMED_DAY_BIT_THU 4 +# define OSSL_NAMED_DAY_BIT_FRI 5 +# define OSSL_NAMED_DAY_BIT_SAT 6 + +typedef struct OSSL_NAMED_DAY_st { + int type; + union { + ASN1_INTEGER *intNamedDays; + ASN1_BIT_STRING *bitNamedDays; + } choice; +} OSSL_NAMED_DAY; + +# define OSSL_TIME_SPEC_X_DAY_OF_FIRST 0 +# define OSSL_TIME_SPEC_X_DAY_OF_SECOND 1 +# define OSSL_TIME_SPEC_X_DAY_OF_THIRD 2 +# define OSSL_TIME_SPEC_X_DAY_OF_FOURTH 3 +# define OSSL_TIME_SPEC_X_DAY_OF_FIFTH 4 + +typedef struct OSSL_TIME_SPEC_X_DAY_OF_st { + int type; + union { + OSSL_NAMED_DAY *first; + OSSL_NAMED_DAY *second; + OSSL_NAMED_DAY *third; + OSSL_NAMED_DAY *fourth; + OSSL_NAMED_DAY *fifth; + } choice; +} OSSL_TIME_SPEC_X_DAY_OF; + +# define OSSL_TIME_SPEC_DAY_TYPE_INT 0 +# define OSSL_TIME_SPEC_DAY_TYPE_BIT 1 +# define OSSL_TIME_SPEC_DAY_TYPE_DAY_OF 2 +# define OSSL_TIME_SPEC_DAY_BIT_SUN 0 +# define OSSL_TIME_SPEC_DAY_BIT_MON 1 +# define OSSL_TIME_SPEC_DAY_BIT_TUE 2 +# define OSSL_TIME_SPEC_DAY_BIT_WED 3 +# define OSSL_TIME_SPEC_DAY_BIT_THU 4 +# define OSSL_TIME_SPEC_DAY_BIT_FRI 5 +# define OSSL_TIME_SPEC_DAY_BIT_SAT 6 +# define OSSL_TIME_SPEC_DAY_INT_SUN 1 +# define OSSL_TIME_SPEC_DAY_INT_MON 2 +# define OSSL_TIME_SPEC_DAY_INT_TUE 3 +# define OSSL_TIME_SPEC_DAY_INT_WED 4 +# define OSSL_TIME_SPEC_DAY_INT_THU 5 +# define OSSL_TIME_SPEC_DAY_INT_FRI 6 +# define OSSL_TIME_SPEC_DAY_INT_SAT 7 + +typedef struct OSSL_TIME_SPEC_DAY_st { + int type; + union { + STACK_OF(ASN1_INTEGER) *intDay; + ASN1_BIT_STRING *bitDay; + OSSL_TIME_SPEC_X_DAY_OF *dayOf; + } choice; +} OSSL_TIME_SPEC_DAY; + +# define OSSL_TIME_SPEC_WEEKS_TYPE_ALL 0 +# define OSSL_TIME_SPEC_WEEKS_TYPE_INT 1 +# define OSSL_TIME_SPEC_WEEKS_TYPE_BIT 2 +# define OSSL_TIME_SPEC_BIT_WEEKS_1 0 +# define OSSL_TIME_SPEC_BIT_WEEKS_2 1 +# define OSSL_TIME_SPEC_BIT_WEEKS_3 2 +# define OSSL_TIME_SPEC_BIT_WEEKS_4 3 +# define OSSL_TIME_SPEC_BIT_WEEKS_5 4 + +typedef struct OSSL_TIME_SPEC_WEEKS_st { + int type; + union { + ASN1_NULL *allWeeks; + STACK_OF(ASN1_INTEGER) *intWeek; + ASN1_BIT_STRING *bitWeek; + } choice; +} OSSL_TIME_SPEC_WEEKS; + +# define OSSL_TIME_SPEC_MONTH_TYPE_ALL 0 +# define OSSL_TIME_SPEC_MONTH_TYPE_INT 1 +# define OSSL_TIME_SPEC_MONTH_TYPE_BIT 2 +# define OSSL_TIME_SPEC_INT_MONTH_JAN 1 +# define OSSL_TIME_SPEC_INT_MONTH_FEB 2 +# define OSSL_TIME_SPEC_INT_MONTH_MAR 3 +# define OSSL_TIME_SPEC_INT_MONTH_APR 4 +# define OSSL_TIME_SPEC_INT_MONTH_MAY 5 +# define OSSL_TIME_SPEC_INT_MONTH_JUN 6 +# define OSSL_TIME_SPEC_INT_MONTH_JUL 7 +# define OSSL_TIME_SPEC_INT_MONTH_AUG 8 +# define OSSL_TIME_SPEC_INT_MONTH_SEP 9 +# define OSSL_TIME_SPEC_INT_MONTH_OCT 10 +# define OSSL_TIME_SPEC_INT_MONTH_NOV 11 +# define OSSL_TIME_SPEC_INT_MONTH_DEC 12 +# define OSSL_TIME_SPEC_BIT_MONTH_JAN 0 +# define OSSL_TIME_SPEC_BIT_MONTH_FEB 1 +# define OSSL_TIME_SPEC_BIT_MONTH_MAR 2 +# define OSSL_TIME_SPEC_BIT_MONTH_APR 3 +# define OSSL_TIME_SPEC_BIT_MONTH_MAY 4 +# define OSSL_TIME_SPEC_BIT_MONTH_JUN 5 +# define OSSL_TIME_SPEC_BIT_MONTH_JUL 6 +# define OSSL_TIME_SPEC_BIT_MONTH_AUG 7 +# define OSSL_TIME_SPEC_BIT_MONTH_SEP 8 +# define OSSL_TIME_SPEC_BIT_MONTH_OCT 9 +# define OSSL_TIME_SPEC_BIT_MONTH_NOV 10 +# define OSSL_TIME_SPEC_BIT_MONTH_DEC 11 + +typedef struct OSSL_TIME_SPEC_MONTH_st { + int type; + union { + ASN1_NULL *allMonths; + STACK_OF(ASN1_INTEGER) *intMonth; + ASN1_BIT_STRING *bitMonth; + } choice; +} OSSL_TIME_SPEC_MONTH; + +typedef struct OSSL_TIME_PERIOD_st { + STACK_OF(OSSL_DAY_TIME_BAND) *timesOfDay; + OSSL_TIME_SPEC_DAY *days; + OSSL_TIME_SPEC_WEEKS *weeks; + OSSL_TIME_SPEC_MONTH *months; + STACK_OF(ASN1_INTEGER) *years; +} OSSL_TIME_PERIOD; + +# define OSSL_TIME_SPEC_TIME_TYPE_ABSOLUTE 0 +# define OSSL_TIME_SPEC_TIME_TYPE_PERIODIC 1 + +typedef struct OSSL_TIME_SPEC_TIME_st { + int type; + union { + OSSL_TIME_SPEC_ABSOLUTE *absolute; + STACK_OF(OSSL_TIME_PERIOD) *periodic; + } choice; +} OSSL_TIME_SPEC_TIME; + +typedef struct OSSL_TIME_SPEC_st { + OSSL_TIME_SPEC_TIME *time; + ASN1_BOOLEAN notThisTime; + ASN1_INTEGER *timeZone; +} OSSL_TIME_SPEC; + +DECLARE_ASN1_FUNCTIONS(OSSL_DAY_TIME) +DECLARE_ASN1_FUNCTIONS(OSSL_DAY_TIME_BAND) +DECLARE_ASN1_FUNCTIONS(OSSL_TIME_SPEC_DAY) +DECLARE_ASN1_FUNCTIONS(OSSL_TIME_SPEC_WEEKS) +DECLARE_ASN1_FUNCTIONS(OSSL_TIME_SPEC_MONTH) +DECLARE_ASN1_FUNCTIONS(OSSL_NAMED_DAY) +DECLARE_ASN1_FUNCTIONS(OSSL_TIME_SPEC_X_DAY_OF) +DECLARE_ASN1_FUNCTIONS(OSSL_TIME_SPEC_ABSOLUTE) +DECLARE_ASN1_FUNCTIONS(OSSL_TIME_SPEC_TIME) +DECLARE_ASN1_FUNCTIONS(OSSL_TIME_SPEC) +DECLARE_ASN1_FUNCTIONS(OSSL_TIME_PERIOD) + +{- + generate_stack_macros("OSSL_TIME_PERIOD"); +-} + +{- + generate_stack_macros("OSSL_DAY_TIME_BAND"); +-} + # ifdef __cplusplus } # endif