diff --git a/crypto/x509/build.info b/crypto/x509/build.info index 87a8b01d84b9f..b349e7203fe3d 100644 --- a/crypto/x509/build.info +++ b/crypto/x509/build.info @@ -20,7 +20,7 @@ SOURCE[../../libcrypto]=\ v3_single_use.c v3_ac_tgt.c v3_audit_id.c v3_bacons.c v3_sda.c \ v3_usernotice.c x_unotice.c x_iserial.c v3_authattid.c v3_iobo.c \ v3_aaa.c v3_attrmap.c v3_ind_iss.c v3_attrdesc.c v3_aaissdist.c \ - v3_rolespec.c + v3_rolespec.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 7e1822ef1dcdb..f57c11fedffa2 100644 --- a/crypto/x509/ext_dat.h +++ b/crypto/x509/ext_dat.h @@ -48,3 +48,4 @@ extern const X509V3_EXT_METHOD ossl_v3_indirect_issuer; extern const X509V3_EXT_METHOD ossl_v3_attribute_descriptor; extern const X509V3_EXT_METHOD ossl_v3_aa_issuing_dist_point; extern const X509V3_EXT_METHOD ossl_v3_role_spec_cert_identifier; +extern const X509V3_EXT_METHOD ossl_v3_time_specification; diff --git a/crypto/x509/standard_exts.h b/crypto/x509/standard_exts.h index d7531e09f3931..6380a2ec300df 100644 --- a/crypto/x509/standard_exts.h +++ b/crypto/x509/standard_exts.h @@ -80,7 +80,7 @@ static const X509V3_EXT_METHOD *standard_exts[] = { &ossl_v3_role_spec_cert_identifier, &ossl_v3_bacons, &ossl_v3_delegated_name_constraints, - // TODO: timeSpecification + &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 0000000000000..1c93c0c69f05f --- /dev/null +++ b/crypto/x509/v3_timespec.c @@ -0,0 +1,800 @@ +/* + * Copyright 1999-2021 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 "internal/cryptlib.h" +#include +#include +#include +#include +#include "ext_dat.h" +#include "x509_local.h" + +ASN1_SEQUENCE(TIME_SPEC_ABSOLUTE) = { + ASN1_EXP_OPT(TIME_SPEC_ABSOLUTE, startTime, ASN1_GENERALIZEDTIME, 0), + ASN1_EXP_OPT(TIME_SPEC_ABSOLUTE, endTime, ASN1_GENERALIZEDTIME, 1), +} ASN1_SEQUENCE_END(TIME_SPEC_ABSOLUTE) + +ASN1_SEQUENCE(DAY_TIME) = { + ASN1_EXP_OPT(DAY_TIME, hour, ASN1_INTEGER, 0), + ASN1_EXP_OPT(DAY_TIME, minute, ASN1_INTEGER, 1), + ASN1_EXP_OPT(DAY_TIME, second, ASN1_INTEGER, 2), +} ASN1_SEQUENCE_END(DAY_TIME) + +ASN1_SEQUENCE(DAY_TIME_BAND) = { + ASN1_EXP_OPT(DAY_TIME_BAND, startDayTime, DAY_TIME, 0), + ASN1_EXP_OPT(DAY_TIME_BAND, endDayTime, DAY_TIME, 1), +} ASN1_SEQUENCE_END(DAY_TIME_BAND) + +ASN1_CHOICE(NAMED_DAY) = { + ASN1_SET_OF(NAMED_DAY, choice.intNamedDays, ASN1_ENUMERATED), + ASN1_SIMPLE(NAMED_DAY, choice.bitNamedDays, ASN1_BIT_STRING), +} ASN1_CHOICE_END(NAMED_DAY) + +ASN1_CHOICE(TIME_SPEC_X_DAY_OF) = { + ASN1_EXP(TIME_SPEC_X_DAY_OF, choice.first, NAMED_DAY, 1), + ASN1_EXP(TIME_SPEC_X_DAY_OF, choice.second, NAMED_DAY, 2), + ASN1_EXP(TIME_SPEC_X_DAY_OF, choice.third, NAMED_DAY, 3), + ASN1_EXP(TIME_SPEC_X_DAY_OF, choice.fourth, NAMED_DAY, 4), + ASN1_EXP(TIME_SPEC_X_DAY_OF, choice.fifth, NAMED_DAY, 5), +} ASN1_CHOICE_END(TIME_SPEC_X_DAY_OF) + +ASN1_CHOICE(TIME_SPEC_DAY) = { + ASN1_SET_OF(TIME_SPEC_DAY, choice.intDay, ASN1_INTEGER), + ASN1_SIMPLE(TIME_SPEC_DAY, choice.bitDay, ASN1_BIT_STRING), + ASN1_SIMPLE(TIME_SPEC_DAY, choice.dayOf, TIME_SPEC_X_DAY_OF), +} ASN1_CHOICE_END(TIME_SPEC_DAY) + +ASN1_CHOICE(TIME_SPEC_WEEKS) = { + ASN1_SIMPLE(TIME_SPEC_WEEKS, choice.allWeeks, ASN1_NULL), + ASN1_SET_OF(TIME_SPEC_WEEKS, choice.intWeek, ASN1_INTEGER), + ASN1_SIMPLE(TIME_SPEC_WEEKS, choice.bitWeek, ASN1_BIT_STRING), +} ASN1_CHOICE_END(TIME_SPEC_WEEKS) + +ASN1_CHOICE(TIME_SPEC_MONTH) = { + ASN1_SIMPLE(TIME_SPEC_MONTH, choice.allMonths, ASN1_NULL), + ASN1_SET_OF(TIME_SPEC_MONTH, choice.intMonth, ASN1_INTEGER), + ASN1_SIMPLE(TIME_SPEC_MONTH, choice.bitMonth, ASN1_BIT_STRING), +} ASN1_CHOICE_END(TIME_SPEC_MONTH) + +ASN1_SEQUENCE(TIME_PERIOD) = { + ASN1_EXP_SET_OF_OPT(TIME_PERIOD, timesOfDay, DAY_TIME_BAND, 0), + ASN1_EXP_OPT(TIME_PERIOD, days, TIME_SPEC_DAY, 1), + ASN1_EXP_OPT(TIME_PERIOD, weeks, TIME_SPEC_WEEKS, 2), + ASN1_EXP_OPT(TIME_PERIOD, months, TIME_SPEC_MONTH, 3), + ASN1_EXP_SET_OF_OPT(TIME_PERIOD, years, ASN1_INTEGER, 4), +} ASN1_SEQUENCE_END(TIME_PERIOD) + +ASN1_CHOICE(TIME_SPEC_TIME) = { + ASN1_SIMPLE(TIME_SPEC_TIME, choice.absolute, TIME_SPEC_ABSOLUTE), + ASN1_SET_OF(TIME_SPEC_TIME, choice.periodic, TIME_PERIOD) +} ASN1_CHOICE_END(TIME_SPEC_TIME) + +ASN1_SEQUENCE(TIME_SPEC) = { + ASN1_SIMPLE(TIME_SPEC, time, TIME_SPEC_TIME), + ASN1_OPT(TIME_SPEC, notThisTime, ASN1_FBOOLEAN), + ASN1_OPT(TIME_SPEC, timeZone, ASN1_INTEGER), +} ASN1_SEQUENCE_END(TIME_SPEC) + +IMPLEMENT_ASN1_FUNCTIONS(TIME_SPEC_ABSOLUTE) +IMPLEMENT_ASN1_FUNCTIONS(TIME_SPEC_TIME) +IMPLEMENT_ASN1_FUNCTIONS(TIME_SPEC) + +static int i2r_TIME_SPEC_ABSOLUTE(X509V3_EXT_METHOD *method, + TIME_SPEC_ABSOLUTE *time, + BIO *out, int indent) +{ + if ( + time->startTime != NULL + && time->endTime != NULL + ) { + BIO_puts(out, "Any time between "); + BIO_printf(out, "%.*s", time->startTime->length, time->startTime->data); + BIO_puts(out, " and "); + BIO_printf(out, "%.*s", time->endTime->length, time->endTime->data); + } else if (time->startTime != NULL) { + BIO_puts(out, "Any time After "); + BIO_printf(out, "%.*s", time->startTime->length, time->startTime->data); + } else if (time->endTime != NULL) { + BIO_puts(out, "Any time until "); + BIO_printf(out, "%.*s", time->endTime->length, time->endTime->data); + } else { // Invalid: there must be SOME time specified. + return BIO_puts(out, "INVALID (EMPTY)"); + } + return 1; +} + +static int i2r_DAY_TIME(X509V3_EXT_METHOD *method, + DAY_TIME *dt, + BIO *out, int indent) +{ + int64_t h; + int64_t m; + int64_t s; + + if (!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, "%02ld:%02ld:%02ld", h, m, s); +} + +static int i2r_DAY_TIME_BAND(X509V3_EXT_METHOD *method, + DAY_TIME_BAND *band, + BIO *out, int indent) +{ + if (band->startDayTime) { + if (!i2r_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_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 (TIME_SPEC_INT_MONTH_JAN): return BIO_puts(out, "JAN"); + case (TIME_SPEC_INT_MONTH_FEB): return BIO_puts(out, "FEB"); + case (TIME_SPEC_INT_MONTH_MAR): return BIO_puts(out, "MAR"); + case (TIME_SPEC_INT_MONTH_APR): return BIO_puts(out, "APR"); + case (TIME_SPEC_INT_MONTH_MAY): return BIO_puts(out, "MAY"); + case (TIME_SPEC_INT_MONTH_JUN): return BIO_puts(out, "JUN"); + case (TIME_SPEC_INT_MONTH_JUL): return BIO_puts(out, "JUL"); + case (TIME_SPEC_INT_MONTH_AUG): return BIO_puts(out, "AUG"); + case (TIME_SPEC_INT_MONTH_SEP): return BIO_puts(out, "SEP"); + case (TIME_SPEC_INT_MONTH_OCT): return BIO_puts(out, "OCT"); + case (TIME_SPEC_INT_MONTH_NOV): return BIO_puts(out, "NOV"); + case (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; + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_MONTH_JAN)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "JAN")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_MONTH_FEB)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "FEB")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_MONTH_MAR)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "MAR")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_MONTH_APR)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "APR")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_MONTH_MAY)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "MAY")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_MONTH_JUN)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "JUN")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_MONTH_JUL)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "JUL")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_MONTH_AUG)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "AUG")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_MONTH_SEP)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "SEP")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_MONTH_OCT)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "OCT")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_MONTH_NOV)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "NOV")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_MONTH_DEC)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "DEC")) { + 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 Rec. X.520. */ +static int print_bit_week (BIO *out, ASN1_BIT_STRING *bs) { + int i; + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_WEEKS_1)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "first")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_WEEKS_2)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "second")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_WEEKS_3)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "third")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_WEEKS_4)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "fourth")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_BIT_WEEKS_5)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "final")) { + return 0; + } + } + return 1; +} + +static int print_day_of_week (BIO *out, ASN1_BIT_STRING *bs) { + int i; + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_DAY_BIT_SUN)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "SUN")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_DAY_BIT_MON)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "MON")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_DAY_BIT_TUE)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "TUE")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_DAY_BIT_WED)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "WED")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_DAY_BIT_THU)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "THU")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_DAY_BIT_FRI)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "FRI")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, TIME_SPEC_DAY_BIT_SAT)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "SAT")) { + return 0; + } + } + return 1; +} + +static int print_int_day_of_week (BIO *out, int64_t month) { + switch (month) { + case (TIME_SPEC_DAY_INT_SUN): return BIO_puts(out, "SUN"); + case (TIME_SPEC_DAY_INT_MON): return BIO_puts(out, "MON"); + case (TIME_SPEC_DAY_INT_TUE): return BIO_puts(out, "TUE"); + case (TIME_SPEC_DAY_INT_WED): return BIO_puts(out, "WED"); + case (TIME_SPEC_DAY_INT_THU): return BIO_puts(out, "THU"); + case (TIME_SPEC_DAY_INT_FRI): return BIO_puts(out, "FRI"); + case (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 (NAMED_DAY_INT_SUN): return BIO_puts(out, "SUN"); + case (NAMED_DAY_INT_MON): return BIO_puts(out, "MON"); + case (NAMED_DAY_INT_TUE): return BIO_puts(out, "TUE"); + case (NAMED_DAY_INT_WED): return BIO_puts(out, "WED"); + case (NAMED_DAY_INT_THU): return BIO_puts(out, "THU"); + case (NAMED_DAY_INT_FRI): return BIO_puts(out, "FRI"); + case (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) { + int i; + if (ASN1_BIT_STRING_get_bit(bs, NAMED_DAY_BIT_SUN)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "SUN")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, NAMED_DAY_BIT_MON)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "MON")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, NAMED_DAY_BIT_TUE)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "TUE")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, NAMED_DAY_BIT_WED)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "WED")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, NAMED_DAY_BIT_THU)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "THU")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, NAMED_DAY_BIT_FRI)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "FRI")) { + return 0; + } + } + if (ASN1_BIT_STRING_get_bit(bs, NAMED_DAY_BIT_SAT)) { + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + i++; + if (!BIO_puts(out, "SAT")) { + return 0; + } + } + return 1; +} + +static int i2r_PERIOD(X509V3_EXT_METHOD *method, + TIME_PERIOD *p, + BIO *out, int indent) +{ + BIO_printf(out, "%*sPeriod:\n", indent, ""); + int i; + if (p->timesOfDay) { + DAY_TIME_BAND *band; + BIO_printf(out, "%*sDaytime bands:\n", indent + 4, ""); + for (i = 0; i < sk_DAY_TIME_BAND_num(p->timesOfDay); i++) { + band = sk_DAY_TIME_BAND_value(p->timesOfDay, i); + BIO_printf(out, "%*s", indent + 8, ""); + if (!i2r_DAY_TIME_BAND(method, band, out, indent + 8)) { + return 0; + } + if (!BIO_puts(out, "\n")) { + return 0; + } + } + if (!BIO_puts(out, "\n")) { + return 0; + } + } + if (p->days) { + if (!BIO_printf(out, "%*sDays: ", indent + 4, "")) { + return 0; + } + switch (p->days->type) { + case (TIME_SPEC_DAY_TYPE_INT): { + for (i = 0; i < sk_ASN1_INTEGER_num(p->days->choice.intDay); i++) { + ASN1_INTEGER *big_day; + int64_t day; + + big_day = sk_ASN1_INTEGER_value(p->days->choice.intDay, i); + if (!ASN1_INTEGER_get_int64(&day, big_day)) { + 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, day)) { + return 0; + } + } else if (!BIO_printf(out, "%ld", day)) { + return 0; + } + } + break; + } + case (TIME_SPEC_DAY_TYPE_BIT): { + if (!print_day_of_week(out, p->days->choice.bitDay)) { + return 0; + } + break; + } + case (TIME_SPEC_DAY_TYPE_DAY_OF): { + NAMED_DAY *nd; + switch (p->days->choice.dayOf->type) { + case (TIME_SPEC_X_DAY_OF_FIRST): { + if (!BIO_puts(out, "FIRST ")) { + return 0; + } + nd = p->days->choice.dayOf->choice.first; + break; + } + case (TIME_SPEC_X_DAY_OF_SECOND): { + if (!BIO_puts(out, "SECOND ")) { + return 0; + } + nd = p->days->choice.dayOf->choice.second; + break; + } + case (TIME_SPEC_X_DAY_OF_THIRD): { + if (!BIO_puts(out, "THIRD ")) { + return 0; + } + nd = p->days->choice.dayOf->choice.third; + break; + } + case (TIME_SPEC_X_DAY_OF_FOURTH): { + if (!BIO_puts(out, "FOURTH ")) { + return 0; + } + nd = p->days->choice.dayOf->choice.fourth; + break; + } + case (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 (NAMED_DAY_TYPE_INT): { + int64_t day; + + if (!ASN1_INTEGER_get_int64(&day, nd->choice.intNamedDays)) { + return 0; + } + if (!print_int_named_day(out, day)) { + return 0; + } + break; + } + case (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 (!BIO_printf(out, "%*sWeeks: ", indent + 4, "")) { + return 0; + } + switch (p->weeks->type) { + case (TIME_SPEC_WEEKS_TYPE_ALL): { + if (!BIO_puts(out, "ALL")) { + return 0; + } + break; + } + case (TIME_SPEC_WEEKS_TYPE_INT): { + for (i = 0; i < sk_ASN1_INTEGER_num(p->weeks->choice.intWeek); i++) { + ASN1_INTEGER *big_week; + int64_t week; + + big_week = sk_ASN1_INTEGER_value(p->weeks->choice.intWeek, i); + if (!ASN1_INTEGER_get_int64(&week, big_week)) { + return 0; + } + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + if (!BIO_printf(out, "%ld", week)) { + return 0; + } + } + break; + } + case (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, "")) { + return 0; + } + switch (p->months->type) { + case (TIME_SPEC_MONTH_TYPE_ALL): { + if (!BIO_puts(out, "ALL")) { + return 0; + } + break; + } + case (TIME_SPEC_MONTH_TYPE_INT): { + for (i = 0; i < sk_ASN1_INTEGER_num(p->months->choice.intMonth); i++) { + ASN1_INTEGER *big_month; + int64_t month; + + big_month = sk_ASN1_INTEGER_value(p->months->choice.intMonth, i); + if (!ASN1_INTEGER_get_int64(&month, big_month)) { + return 0; + } + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + if (!print_int_month(out, month)) { + return 0; + } + } + break; + } + case (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, "")) { + return 0; + } + for (i = 0; i < sk_ASN1_INTEGER_num(p->years); i++) { + ASN1_INTEGER *big_year; + int64_t year; + + big_year = sk_ASN1_INTEGER_value(p->years, i); + if (!ASN1_INTEGER_get_int64(&year, big_year)) { + return 0; + } + if (i > 0 && !BIO_puts(out, ", ")) { + return 0; + } + if (!BIO_printf(out, "%04ld", year)) { + return 0; + } + } + } + return 1; +} + +static int i2r_TIME_SPEC_TIME(X509V3_EXT_METHOD *method, + TIME_SPEC_TIME *time, + BIO *out, int indent) +{ + TIME_PERIOD *tp; + int i; + switch (time->type) { + case (TIME_SPEC_TIME_TYPE_ABSOLUTE): { + BIO_printf(out, "%*sAbsolute: ", indent, ""); + i2r_TIME_SPEC_ABSOLUTE(method, time->choice.absolute, out, indent + 4); + return BIO_puts(out, "\n"); + return 1; + } + case (TIME_SPEC_TIME_TYPE_PERIODIC): { + BIO_printf(out, "%*sPeriodic:\n", indent, ""); + for (i = 0; i < sk_TIME_PERIOD_num(time->choice.periodic); i++) { + if (i > 0 && !BIO_puts(out, "\n")) { + return 0; + } + tp = sk_TIME_PERIOD_value(time->choice.periodic, i); + if (!i2r_PERIOD(method, tp, out, indent + 4)) { + return 0; + } + } + return BIO_puts(out, "\n"); + } + default: return 0; + } + return 0; +} + +static int i2r_TIME_SPEC(X509V3_EXT_METHOD *method, + TIME_SPEC *time, + BIO *out, int indent) +{ + if (time->timeZone) { + int64_t tz; + if (ASN1_INTEGER_get_int64(&tz, time->timeZone) != 1) { + return 0; + } + BIO_printf(out, "%*sUTC Offset: %+ld\n", indent, "", tz); + } + if (time->notThisTime > 0) { + BIO_printf(out, "%*sNOT this time:\n", indent, ""); + } else { + BIO_printf(out, "%*sTime:\n", indent, ""); + } + return i2r_TIME_SPEC_TIME(method, time->time, out, indent + 4); +} + +const X509V3_EXT_METHOD ossl_v3_time_specification = { + NID_time_specification, 0, + ASN1_ITEM_ref(TIME_SPEC), + 0, 0, 0, 0, + 0, 0, + 0, + 0, + (X509V3_EXT_I2R)i2r_TIME_SPEC, + NULL, + NULL +}; \ No newline at end of file diff --git a/include/openssl/x509v3.h.in b/include/openssl/x509v3.h.in index 7d52b2fdf88bd..d1ba16bf44f21 100644 --- a/include/openssl/x509v3.h.in +++ b/include/openssl/x509v3.h.in @@ -1223,6 +1223,184 @@ typedef STACK_OF(ROLE_SPEC_CERT_ID) ROLE_SPEC_CERT_ID_SYNTAX; DECLARE_ASN1_FUNCTIONS(ROLE_SPEC_CERT_ID_SYNTAX) +typedef struct TIME_SPEC_ABSOLUTE_st { + ASN1_GENERALIZEDTIME *startTime; + ASN1_GENERALIZEDTIME *endTime; +} TIME_SPEC_ABSOLUTE; + +typedef struct DAY_TIME_st { + ASN1_INTEGER *hour; + ASN1_INTEGER *minute; + ASN1_INTEGER *second; +} DAY_TIME; + +typedef struct DAY_TIME_BAND_st { + DAY_TIME *startDayTime; + DAY_TIME *endDayTime; +} DAY_TIME_BAND; + +#define NAMED_DAY_TYPE_INT 0 +#define NAMED_DAY_TYPE_BIT 1 +#define NAMED_DAY_INT_SUN 1 +#define NAMED_DAY_INT_MON 2 +#define NAMED_DAY_INT_TUE 3 +#define NAMED_DAY_INT_WED 4 +#define NAMED_DAY_INT_THU 5 +#define NAMED_DAY_INT_FRI 6 +#define NAMED_DAY_INT_SAT 7 +#define NAMED_DAY_BIT_SUN 0 +#define NAMED_DAY_BIT_MON 1 +#define NAMED_DAY_BIT_TUE 2 +#define NAMED_DAY_BIT_WED 3 +#define NAMED_DAY_BIT_THU 4 +#define NAMED_DAY_BIT_FRI 5 +#define NAMED_DAY_BIT_SAT 6 + +typedef struct NAMED_DAY_st { + int type; + union { + ASN1_INTEGER *intNamedDays; + ASN1_BIT_STRING *bitNamedDays; + } choice; +} NAMED_DAY; + +#define TIME_SPEC_X_DAY_OF_FIRST 0 +#define TIME_SPEC_X_DAY_OF_SECOND 1 +#define TIME_SPEC_X_DAY_OF_THIRD 2 +#define TIME_SPEC_X_DAY_OF_FOURTH 3 +#define TIME_SPEC_X_DAY_OF_FIFTH 4 + +typedef struct TIME_SPEC_X_DAY_OF_st { + int type; + union { + NAMED_DAY *first; + NAMED_DAY *second; + NAMED_DAY *third; + NAMED_DAY *fourth; + NAMED_DAY *fifth; + } choice; +} TIME_SPEC_X_DAY_OF; + +#define TIME_SPEC_DAY_TYPE_INT 0 +#define TIME_SPEC_DAY_TYPE_BIT 1 +#define TIME_SPEC_DAY_TYPE_DAY_OF 2 +#define TIME_SPEC_DAY_BIT_SUN 0 +#define TIME_SPEC_DAY_BIT_MON 1 +#define TIME_SPEC_DAY_BIT_TUE 2 +#define TIME_SPEC_DAY_BIT_WED 3 +#define TIME_SPEC_DAY_BIT_THU 4 +#define TIME_SPEC_DAY_BIT_FRI 5 +#define TIME_SPEC_DAY_BIT_SAT 6 +#define TIME_SPEC_DAY_INT_SUN 1 +#define TIME_SPEC_DAY_INT_MON 2 +#define TIME_SPEC_DAY_INT_TUE 3 +#define TIME_SPEC_DAY_INT_WED 4 +#define TIME_SPEC_DAY_INT_THU 5 +#define TIME_SPEC_DAY_INT_FRI 6 +#define TIME_SPEC_DAY_INT_SAT 7 + +typedef struct TIME_SPEC_DAY_st { + int type; + union { + STACK_OF(ASN1_INTEGER) *intDay; + ASN1_BIT_STRING *bitDay; + TIME_SPEC_X_DAY_OF *dayOf; + } choice; +} TIME_SPEC_DAY; + +#define TIME_SPEC_WEEKS_TYPE_ALL 0 +#define TIME_SPEC_WEEKS_TYPE_INT 1 +#define TIME_SPEC_WEEKS_TYPE_BIT 2 +#define TIME_SPEC_BIT_WEEKS_1 0 +#define TIME_SPEC_BIT_WEEKS_2 1 +#define TIME_SPEC_BIT_WEEKS_3 2 +#define TIME_SPEC_BIT_WEEKS_4 3 +#define TIME_SPEC_BIT_WEEKS_5 4 + +typedef struct TIME_SPEC_WEEKS_st { + int type; + union { + ASN1_NULL *allWeeks; + STACK_OF(ASN1_INTEGER) *intWeek; + ASN1_BIT_STRING *bitWeek; + } choice; +} TIME_SPEC_WEEKS; + +#define TIME_SPEC_MONTH_TYPE_ALL 0 +#define TIME_SPEC_MONTH_TYPE_INT 1 +#define TIME_SPEC_MONTH_TYPE_BIT 2 +#define TIME_SPEC_INT_MONTH_JAN 1 +#define TIME_SPEC_INT_MONTH_FEB 2 +#define TIME_SPEC_INT_MONTH_MAR 3 +#define TIME_SPEC_INT_MONTH_APR 4 +#define TIME_SPEC_INT_MONTH_MAY 5 +#define TIME_SPEC_INT_MONTH_JUN 6 +#define TIME_SPEC_INT_MONTH_JUL 7 +#define TIME_SPEC_INT_MONTH_AUG 8 +#define TIME_SPEC_INT_MONTH_SEP 9 +#define TIME_SPEC_INT_MONTH_OCT 10 +#define TIME_SPEC_INT_MONTH_NOV 11 +#define TIME_SPEC_INT_MONTH_DEC 12 +#define TIME_SPEC_BIT_MONTH_JAN 0 +#define TIME_SPEC_BIT_MONTH_FEB 1 +#define TIME_SPEC_BIT_MONTH_MAR 2 +#define TIME_SPEC_BIT_MONTH_APR 3 +#define TIME_SPEC_BIT_MONTH_MAY 4 +#define TIME_SPEC_BIT_MONTH_JUN 5 +#define TIME_SPEC_BIT_MONTH_JUL 6 +#define TIME_SPEC_BIT_MONTH_AUG 7 +#define TIME_SPEC_BIT_MONTH_SEP 8 +#define TIME_SPEC_BIT_MONTH_OCT 9 +#define TIME_SPEC_BIT_MONTH_NOV 10 +#define TIME_SPEC_BIT_MONTH_DEC 11 + +typedef struct TIME_SPEC_MONTH_st { + int type; + union { + ASN1_NULL *allMonths; + STACK_OF(ASN1_INTEGER) *intMonth; + ASN1_BIT_STRING *bitMonth; + } choice; +} TIME_SPEC_MONTH; + +typedef struct TIME_PERIOD_st { + STACK_OF(DAY_TIME_BAND) *timesOfDay; + TIME_SPEC_DAY *days; + TIME_SPEC_WEEKS *weeks; + TIME_SPEC_MONTH *months; + STACK_OF(ASN1_INTEGER) *years; +} TIME_PERIOD; + +#define TIME_SPEC_TIME_TYPE_ABSOLUTE 0 +#define TIME_SPEC_TIME_TYPE_PERIODIC 1 + +typedef struct TIME_SPEC_TIME_st { + int type; + union { + TIME_SPEC_ABSOLUTE *absolute; + STACK_OF(TIME_PERIOD) *periodic; + } choice; +} TIME_SPEC_TIME; + +typedef struct TIME_SPEC_st { + TIME_SPEC_TIME *time; + ASN1_BOOLEAN notThisTime; + ASN1_INTEGER *timeZone; +} TIME_SPEC; + +DECLARE_ASN1_FUNCTIONS(TIME_SPEC_ABSOLUTE) +DECLARE_ASN1_FUNCTIONS(TIME_SPEC_TIME) +DECLARE_ASN1_FUNCTIONS(TIME_SPEC) +DECLARE_ASN1_FUNCTIONS(TIME_PERIOD) +{- + generate_stack_macros("TIME_PERIOD"); +-} + +DECLARE_ASN1_FUNCTIONS(DAY_TIME_BAND) +{- + generate_stack_macros("DAY_TIME_BAND"); +-} + # ifdef __cplusplus } # endif diff --git a/test/certs/ext-timeSpecification-absolute.pem b/test/certs/ext-timeSpecification-absolute.pem new file mode 100644 index 0000000000000..8ce07092d5f83 --- /dev/null +++ b/test/certs/ext-timeSpecification-absolute.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB2jCCAcSgAwIBAgIEDCI4TjANBgkqhkiG9w0BAQUFADARMQ8wDQYDVQQDDAZI +aSBtb20wIhgPMjAyMjEyMjAxMzA3MjFaGA8yMDIyMTIyMDEzMDcyMVowETEPMA0G +A1UEAwwGSGkgbW9tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtnjL +m1ts1hC4fNNt3UnQD9y73bDXgioTyWYSI3ca/KNfuTydjFTEYAmqnuGrBOUfgbmH +3PRQ0AmpqljgWTb3d3K8H4UFvDWQTPSS21IMjm8oqd19nE5GxWirGu0oDRzhWLHe +1RZ7ZrohCPg/1Ocsy47QZuK2laFB0rEmrRWBmEYbDl3/wxf5XfqIqpOynJB02thX +rTCcTM7Rz1FqCFt/ZVZB5hKY2S+CTdE9OIVKlr4WHMfuvUYeOj06GkwLFJHNv2tU ++tovI3mYRxUuY4UupkS3MC+Otey7XKm1P+INjWWoegm6iCAt3VuspVz+6pU2xgl3 +nrAVMQHB4fReQPH0pQIDAQABozgwNjA0BgNVHSsELTArMCagERgPMjAyMjEyMjAx +MzA3MjFaoREYDzIwMjIxMjIwMTMwNzIxWgIB+zANBgkqhkiG9w0BAQUFAAMBAA== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/test/certs/ext-timeSpecification-periodic.pem b/test/certs/ext-timeSpecification-periodic.pem new file mode 100644 index 0000000000000..171e2a7a81732 --- /dev/null +++ b/test/certs/ext-timeSpecification-periodic.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICNjCCAiCgAwIBAgIEDCI4TjANBgkqhkiG9w0BAQUFADARMQ8wDQYDVQQDDAZI +aSBtb20wIhgPMjAyMjEyMjExNDQ5NDJaGA8yMDIyMTIyMTE0NDk0MlowETEPMA0G +A1UEAwwGSGkgbW9tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtnjL +m1ts1hC4fNNt3UnQD9y73bDXgioTyWYSI3ca/KNfuTydjFTEYAmqnuGrBOUfgbmH +3PRQ0AmpqljgWTb3d3K8H4UFvDWQTPSS21IMjm8oqd19nE5GxWirGu0oDRzhWLHe +1RZ7ZrohCPg/1Ocsy47QZuK2laFB0rEmrRWBmEYbDl3/wxf5XfqIqpOynJB02thX +rTCcTM7Rz1FqCFt/ZVZB5hKY2S+CTdE9OIVKlr4WHMfuvUYeOj06GkwLFJHNv2tU ++tovI3mYRxUuY4UupkS3MC+Otey7XKm1P+INjWWoegm6iCAt3VuspVz+6pU2xgl3 +nrAVMQHB4fReQPH0pQIDAQABo4GTMIGQMIGNBgNVHSsEgYUwgYIxejBWoCoxKDAm +oBEwD6ADAgEFoQMCASuiAwIBFaERMA+gAwIBDKEDAgEiogMCATihCDEGAgEBAgEC +oggxBgIBAwIBBKMIMQYCAQUCAQakCjEIAgIH5gICB+cwIKEIMQYCAQMCAQSjCDEG +AgEHAgEIpAoxCAICB+cCAgfoAQH/AgH7MA0GCSqGSIb3DQEBBQUAAwEA +-----END CERTIFICATE----- \ No newline at end of file diff --git a/util/libcrypto.num b/util/libcrypto.num index 758192aabe715..6cce5522ef553 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5685,3 +5685,28 @@ i2d_ROLE_SPEC_CERT_ID_SYNTAX ? 3_2_0 EXIST::FUNCTION: ROLE_SPEC_CERT_ID_SYNTAX_free ? 3_2_0 EXIST::FUNCTION: ROLE_SPEC_CERT_ID_SYNTAX_new ? 3_2_0 EXIST::FUNCTION: ROLE_SPEC_CERT_ID_SYNTAX_it ? 3_2_0 EXIST::FUNCTION: +d2i_TIME_SPEC_ABSOLUTE ? 3_2_0 EXIST::FUNCTION: +i2d_TIME_SPEC_ABSOLUTE ? 3_2_0 EXIST::FUNCTION: +TIME_SPEC_ABSOLUTE_free ? 3_2_0 EXIST::FUNCTION: +TIME_SPEC_ABSOLUTE_new ? 3_2_0 EXIST::FUNCTION: +TIME_SPEC_ABSOLUTE_it ? 3_2_0 EXIST::FUNCTION: +d2i_TIME_SPEC_TIME ? 3_2_0 EXIST::FUNCTION: +i2d_TIME_SPEC_TIME ? 3_2_0 EXIST::FUNCTION: +TIME_SPEC_TIME_free ? 3_2_0 EXIST::FUNCTION: +TIME_SPEC_TIME_new ? 3_2_0 EXIST::FUNCTION: +TIME_SPEC_TIME_it ? 3_2_0 EXIST::FUNCTION: +d2i_TIME_SPEC ? 3_2_0 EXIST::FUNCTION: +i2d_TIME_SPEC ? 3_2_0 EXIST::FUNCTION: +TIME_SPEC_free ? 3_2_0 EXIST::FUNCTION: +TIME_SPEC_new ? 3_2_0 EXIST::FUNCTION: +TIME_SPEC_it ? 3_2_0 EXIST::FUNCTION: +d2i_TIME_PERIOD ? 3_2_0 EXIST::FUNCTION: +i2d_TIME_PERIOD ? 3_2_0 EXIST::FUNCTION: +TIME_PERIOD_free ? 3_2_0 EXIST::FUNCTION: +TIME_PERIOD_new ? 3_2_0 EXIST::FUNCTION: +TIME_PERIOD_it ? 3_2_0 EXIST::FUNCTION: +d2i_DAY_TIME_BAND ? 3_2_0 EXIST::FUNCTION: +i2d_DAY_TIME_BAND ? 3_2_0 EXIST::FUNCTION: +DAY_TIME_BAND_free ? 3_2_0 EXIST::FUNCTION: +DAY_TIME_BAND_new ? 3_2_0 EXIST::FUNCTION: +DAY_TIME_BAND_it ? 3_2_0 EXIST::FUNCTION: