xref: /freebsd/crypto/openssl/crypto/x509/v3_timespec.c (revision 10a428653ee7216475f1ddce3fb4cbf1200319f8)
1 /*
2  * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include <stdio.h>
11 #include <openssl/asn1t.h>
12 #include <openssl/x509v3.h>
13 #include <crypto/asn1.h>
14 #include "ext_dat.h"
15 
16 static const char *WEEKDAY_NAMES[7] = {
17     "SUN",
18     "MON",
19     "TUE",
20     "WED",
21     "THU",
22     "FRI",
23     "SAT"
24 };
25 
26 static const char *WEEK_NAMES[5] = {
27     "first",
28     "second",
29     "third",
30     "fourth",
31     "final"
32 };
33 
34 static const char *MONTH_NAMES[12] = {
35     "JAN",
36     "FEB",
37     "MAR",
38     "APR",
39     "MAY",
40     "JUN",
41     "JUL",
42     "AUG",
43     "SEPT",
44     "OCT",
45     "NOV",
46     "DEC"
47 };
48 
49 ASN1_SEQUENCE(OSSL_TIME_SPEC_ABSOLUTE) = {
50     ASN1_EXP_OPT(OSSL_TIME_SPEC_ABSOLUTE, startTime, ASN1_GENERALIZEDTIME, 0),
51     ASN1_EXP_OPT(OSSL_TIME_SPEC_ABSOLUTE, endTime, ASN1_GENERALIZEDTIME, 1),
52 } ASN1_SEQUENCE_END(OSSL_TIME_SPEC_ABSOLUTE)
53 
54 ASN1_SEQUENCE(OSSL_DAY_TIME) = {
55     ASN1_EXP_OPT(OSSL_DAY_TIME, hour, ASN1_INTEGER, 0),
56     ASN1_EXP_OPT(OSSL_DAY_TIME, minute, ASN1_INTEGER, 1),
57     ASN1_EXP_OPT(OSSL_DAY_TIME, second, ASN1_INTEGER, 2),
58 } ASN1_SEQUENCE_END(OSSL_DAY_TIME)
59 
60 ASN1_SEQUENCE(OSSL_DAY_TIME_BAND) = {
61     ASN1_EXP_OPT(OSSL_DAY_TIME_BAND, startDayTime, OSSL_DAY_TIME, 0),
62     ASN1_EXP_OPT(OSSL_DAY_TIME_BAND, endDayTime, OSSL_DAY_TIME, 1),
63 } ASN1_SEQUENCE_END(OSSL_DAY_TIME_BAND)
64 
65 ASN1_CHOICE(OSSL_NAMED_DAY) = {
66     ASN1_SET_OF(OSSL_NAMED_DAY, choice.intNamedDays, ASN1_ENUMERATED),
67     ASN1_SIMPLE(OSSL_NAMED_DAY, choice.bitNamedDays, ASN1_BIT_STRING),
68 } ASN1_CHOICE_END(OSSL_NAMED_DAY)
69 
70 ASN1_CHOICE(OSSL_TIME_SPEC_X_DAY_OF) = {
71     ASN1_EXP(OSSL_TIME_SPEC_X_DAY_OF, choice.first, OSSL_NAMED_DAY, 1),
72     ASN1_EXP(OSSL_TIME_SPEC_X_DAY_OF, choice.second, OSSL_NAMED_DAY, 2),
73     ASN1_EXP(OSSL_TIME_SPEC_X_DAY_OF, choice.third, OSSL_NAMED_DAY, 3),
74     ASN1_EXP(OSSL_TIME_SPEC_X_DAY_OF, choice.fourth, OSSL_NAMED_DAY, 4),
75     ASN1_EXP(OSSL_TIME_SPEC_X_DAY_OF, choice.fifth, OSSL_NAMED_DAY, 5),
76 } ASN1_CHOICE_END(OSSL_TIME_SPEC_X_DAY_OF)
77 
78 ASN1_CHOICE(OSSL_TIME_SPEC_DAY) = {
79     ASN1_SET_OF(OSSL_TIME_SPEC_DAY, choice.intDay, ASN1_INTEGER),
80     ASN1_SIMPLE(OSSL_TIME_SPEC_DAY, choice.bitDay, ASN1_BIT_STRING),
81     ASN1_SIMPLE(OSSL_TIME_SPEC_DAY, choice.dayOf, OSSL_TIME_SPEC_X_DAY_OF),
82 } ASN1_CHOICE_END(OSSL_TIME_SPEC_DAY)
83 
84 ASN1_CHOICE(OSSL_TIME_SPEC_WEEKS) = {
85     ASN1_SIMPLE(OSSL_TIME_SPEC_WEEKS, choice.allWeeks, ASN1_NULL),
86     ASN1_SET_OF(OSSL_TIME_SPEC_WEEKS, choice.intWeek, ASN1_INTEGER),
87     ASN1_SIMPLE(OSSL_TIME_SPEC_WEEKS, choice.bitWeek, ASN1_BIT_STRING),
88 } ASN1_CHOICE_END(OSSL_TIME_SPEC_WEEKS)
89 
90 ASN1_CHOICE(OSSL_TIME_SPEC_MONTH) = {
91     ASN1_SIMPLE(OSSL_TIME_SPEC_MONTH, choice.allMonths, ASN1_NULL),
92     ASN1_SET_OF(OSSL_TIME_SPEC_MONTH, choice.intMonth, ASN1_INTEGER),
93     ASN1_SIMPLE(OSSL_TIME_SPEC_MONTH, choice.bitMonth, ASN1_BIT_STRING),
94 } ASN1_CHOICE_END(OSSL_TIME_SPEC_MONTH)
95 
96 ASN1_SEQUENCE(OSSL_TIME_PERIOD) = {
97     ASN1_EXP_SET_OF_OPT(OSSL_TIME_PERIOD, timesOfDay, OSSL_DAY_TIME_BAND, 0),
98     ASN1_EXP_OPT(OSSL_TIME_PERIOD, days, OSSL_TIME_SPEC_DAY, 1),
99     ASN1_EXP_OPT(OSSL_TIME_PERIOD, weeks, OSSL_TIME_SPEC_WEEKS, 2),
100     ASN1_EXP_OPT(OSSL_TIME_PERIOD, months, OSSL_TIME_SPEC_MONTH, 3),
101     ASN1_EXP_SET_OF_OPT(OSSL_TIME_PERIOD, years, ASN1_INTEGER, 4),
102 } ASN1_SEQUENCE_END(OSSL_TIME_PERIOD)
103 
104 ASN1_CHOICE(OSSL_TIME_SPEC_TIME) = {
105     ASN1_SIMPLE(OSSL_TIME_SPEC_TIME, choice.absolute, OSSL_TIME_SPEC_ABSOLUTE),
106     ASN1_SET_OF(OSSL_TIME_SPEC_TIME, choice.periodic, OSSL_TIME_PERIOD)
107 } ASN1_CHOICE_END(OSSL_TIME_SPEC_TIME)
108 
109 ASN1_SEQUENCE(OSSL_TIME_SPEC) = {
110     ASN1_SIMPLE(OSSL_TIME_SPEC, time, OSSL_TIME_SPEC_TIME),
111     ASN1_OPT(OSSL_TIME_SPEC, notThisTime, ASN1_FBOOLEAN),
112     ASN1_OPT(OSSL_TIME_SPEC, timeZone, ASN1_INTEGER),
113 } ASN1_SEQUENCE_END(OSSL_TIME_SPEC)
114 
115 IMPLEMENT_ASN1_FUNCTIONS(OSSL_DAY_TIME)
116 IMPLEMENT_ASN1_FUNCTIONS(OSSL_DAY_TIME_BAND)
117 IMPLEMENT_ASN1_FUNCTIONS(OSSL_TIME_SPEC_DAY)
118 IMPLEMENT_ASN1_FUNCTIONS(OSSL_TIME_SPEC_WEEKS)
119 IMPLEMENT_ASN1_FUNCTIONS(OSSL_TIME_SPEC_MONTH)
120 IMPLEMENT_ASN1_FUNCTIONS(OSSL_NAMED_DAY)
121 IMPLEMENT_ASN1_FUNCTIONS(OSSL_TIME_SPEC_X_DAY_OF)
122 IMPLEMENT_ASN1_FUNCTIONS(OSSL_TIME_SPEC_ABSOLUTE)
123 IMPLEMENT_ASN1_FUNCTIONS(OSSL_TIME_SPEC_TIME)
124 IMPLEMENT_ASN1_FUNCTIONS(OSSL_TIME_SPEC)
125 IMPLEMENT_ASN1_FUNCTIONS(OSSL_TIME_PERIOD)
126 
127 static int i2r_OSSL_TIME_SPEC_ABSOLUTE(X509V3_EXT_METHOD *method,
128     OSSL_TIME_SPEC_ABSOLUTE *time,
129     BIO *out, int indent)
130 {
131     if (time->startTime != NULL && time->endTime != NULL) {
132         if (!BIO_puts(out, "Any time between "))
133             return 0;
134         if (!ossl_asn1_time_print_ex(out, time->startTime, 0))
135             return 0;
136         if (!BIO_puts(out, " and "))
137             return 0;
138         if (!ossl_asn1_time_print_ex(out, time->endTime, 0))
139             return 0;
140     } else if (time->startTime != NULL) {
141         if (!BIO_puts(out, "Any time after "))
142             return 0;
143         if (!ossl_asn1_time_print_ex(out, time->startTime, 0))
144             return 0;
145         if (BIO_printf(out, "%.*s", time->startTime->length, time->startTime->data) <= 0)
146             return 0;
147     } else if (time->endTime != NULL) {
148         if (!BIO_puts(out, "Any time until "))
149             return 0;
150         if (!ossl_asn1_time_print_ex(out, time->endTime, 0))
151             return 0;
152     } else { /* Invalid: there must be SOME time specified. */
153         return BIO_puts(out, "INVALID (EMPTY)");
154     }
155     return 1;
156 }
157 
i2r_OSSL_DAY_TIME(X509V3_EXT_METHOD * method,OSSL_DAY_TIME * dt,BIO * out,int indent)158 static int i2r_OSSL_DAY_TIME(X509V3_EXT_METHOD *method,
159     OSSL_DAY_TIME *dt,
160     BIO *out, int indent)
161 {
162     int64_t h = 0;
163     int64_t m = 0;
164     int64_t s = 0;
165 
166     if (!dt->hour || !ASN1_INTEGER_get_int64(&h, dt->hour))
167         return 0;
168     if (dt->minute && !ASN1_INTEGER_get_int64(&m, dt->minute))
169         return 0;
170     if (dt->second && !ASN1_INTEGER_get_int64(&s, dt->second))
171         return 0;
172     return BIO_printf(out, "%02lld:%02lld:%02lld",
173                (long long int)h, (long long int)m, (long long int)s)
174         > 0;
175 }
176 
i2r_OSSL_DAY_TIME_BAND(X509V3_EXT_METHOD * method,OSSL_DAY_TIME_BAND * band,BIO * out,int indent)177 static int i2r_OSSL_DAY_TIME_BAND(X509V3_EXT_METHOD *method,
178     OSSL_DAY_TIME_BAND *band,
179     BIO *out, int indent)
180 {
181     if (band->startDayTime) {
182         if (!i2r_OSSL_DAY_TIME(method, band->startDayTime, out, indent))
183             return 0;
184     } else if (!BIO_puts(out, "00:00:00")) {
185         return 0;
186     }
187     if (!BIO_puts(out, " - "))
188         return 0;
189     if (band->endDayTime) {
190         if (!i2r_OSSL_DAY_TIME(method, band->endDayTime, out, indent))
191             return 0;
192     } else if (!BIO_puts(out, "23:59:59")) {
193         return 0;
194     }
195     return 1;
196 }
197 
print_int_month(BIO * out,int64_t month)198 static int print_int_month(BIO *out, int64_t month)
199 {
200     switch (month) {
201     case (OSSL_TIME_SPEC_INT_MONTH_JAN):
202         return BIO_puts(out, "JAN");
203     case (OSSL_TIME_SPEC_INT_MONTH_FEB):
204         return BIO_puts(out, "FEB");
205     case (OSSL_TIME_SPEC_INT_MONTH_MAR):
206         return BIO_puts(out, "MAR");
207     case (OSSL_TIME_SPEC_INT_MONTH_APR):
208         return BIO_puts(out, "APR");
209     case (OSSL_TIME_SPEC_INT_MONTH_MAY):
210         return BIO_puts(out, "MAY");
211     case (OSSL_TIME_SPEC_INT_MONTH_JUN):
212         return BIO_puts(out, "JUN");
213     case (OSSL_TIME_SPEC_INT_MONTH_JUL):
214         return BIO_puts(out, "JUL");
215     case (OSSL_TIME_SPEC_INT_MONTH_AUG):
216         return BIO_puts(out, "AUG");
217     case (OSSL_TIME_SPEC_INT_MONTH_SEP):
218         return BIO_puts(out, "SEP");
219     case (OSSL_TIME_SPEC_INT_MONTH_OCT):
220         return BIO_puts(out, "OCT");
221     case (OSSL_TIME_SPEC_INT_MONTH_NOV):
222         return BIO_puts(out, "NOV");
223     case (OSSL_TIME_SPEC_INT_MONTH_DEC):
224         return BIO_puts(out, "DEC");
225     default:
226         return 0;
227     }
228     return 0;
229 }
230 
print_bit_month(BIO * out,ASN1_BIT_STRING * bs)231 static int print_bit_month(BIO *out, ASN1_BIT_STRING *bs)
232 {
233     int i = OSSL_TIME_SPEC_BIT_MONTH_JAN;
234     int j = 0;
235 
236     for (; i <= OSSL_TIME_SPEC_BIT_MONTH_DEC; i++) {
237         if (ASN1_BIT_STRING_get_bit(bs, i)) {
238             if (j > 0 && !BIO_puts(out, ", "))
239                 return 0;
240             j++;
241             if (!BIO_puts(out, MONTH_NAMES[i]))
242                 return 0;
243         }
244     }
245     return 1;
246 }
247 
248 /*
249  * It might seem like you could just print the bits of the string numerically,
250  * but the fifth bit has the special meaning of "the final week" imputed to it
251  * by the text of ITU-T Recommendation X.520.
252  */
print_bit_week(BIO * out,ASN1_BIT_STRING * bs)253 static int print_bit_week(BIO *out, ASN1_BIT_STRING *bs)
254 {
255     int i = OSSL_TIME_SPEC_BIT_WEEKS_1;
256     int j = 0;
257 
258     for (; i <= OSSL_TIME_SPEC_BIT_WEEKS_5; i++) {
259         if (ASN1_BIT_STRING_get_bit(bs, i)) {
260             if (j > 0 && !BIO_puts(out, ", "))
261                 return 0;
262             j++;
263             if (!BIO_puts(out, WEEK_NAMES[i]))
264                 return 0;
265         }
266     }
267     return 1;
268 }
269 
print_day_of_week(BIO * out,ASN1_BIT_STRING * bs)270 static int print_day_of_week(BIO *out, ASN1_BIT_STRING *bs)
271 {
272     int i = OSSL_TIME_SPEC_DAY_BIT_SUN;
273     int j = 0;
274 
275     for (; i <= OSSL_TIME_SPEC_DAY_BIT_SAT; i++) {
276         if (ASN1_BIT_STRING_get_bit(bs, i)) {
277             if (j > 0 && !BIO_puts(out, ", "))
278                 return 0;
279             j++;
280             if (!BIO_puts(out, WEEKDAY_NAMES[i]))
281                 return 0;
282         }
283     }
284     return 1;
285 }
286 
print_int_day_of_week(BIO * out,int64_t dow)287 static int print_int_day_of_week(BIO *out, int64_t dow)
288 {
289     switch (dow) {
290     case (OSSL_TIME_SPEC_DAY_INT_SUN):
291         return BIO_puts(out, "SUN");
292     case (OSSL_TIME_SPEC_DAY_INT_MON):
293         return BIO_puts(out, "MON");
294     case (OSSL_TIME_SPEC_DAY_INT_TUE):
295         return BIO_puts(out, "TUE");
296     case (OSSL_TIME_SPEC_DAY_INT_WED):
297         return BIO_puts(out, "WED");
298     case (OSSL_TIME_SPEC_DAY_INT_THU):
299         return BIO_puts(out, "THU");
300     case (OSSL_TIME_SPEC_DAY_INT_FRI):
301         return BIO_puts(out, "FRI");
302     case (OSSL_TIME_SPEC_DAY_INT_SAT):
303         return BIO_puts(out, "SAT");
304     default:
305         return 0;
306     }
307     return 0;
308 }
309 
print_int_named_day(BIO * out,int64_t nd)310 static int print_int_named_day(BIO *out, int64_t nd)
311 {
312     switch (nd) {
313     case (OSSL_NAMED_DAY_INT_SUN):
314         return BIO_puts(out, "SUN");
315     case (OSSL_NAMED_DAY_INT_MON):
316         return BIO_puts(out, "MON");
317     case (OSSL_NAMED_DAY_INT_TUE):
318         return BIO_puts(out, "TUE");
319     case (OSSL_NAMED_DAY_INT_WED):
320         return BIO_puts(out, "WED");
321     case (OSSL_NAMED_DAY_INT_THU):
322         return BIO_puts(out, "THU");
323     case (OSSL_NAMED_DAY_INT_FRI):
324         return BIO_puts(out, "FRI");
325     case (OSSL_NAMED_DAY_INT_SAT):
326         return BIO_puts(out, "SAT");
327     default:
328         return 0;
329     }
330     return 0;
331 }
332 
print_bit_named_day(BIO * out,ASN1_BIT_STRING * bs)333 static int print_bit_named_day(BIO *out, ASN1_BIT_STRING *bs)
334 {
335     return print_day_of_week(out, bs);
336 }
337 
i2r_OSSL_PERIOD(X509V3_EXT_METHOD * method,OSSL_TIME_PERIOD * p,BIO * out,int indent)338 static int i2r_OSSL_PERIOD(X509V3_EXT_METHOD *method,
339     OSSL_TIME_PERIOD *p,
340     BIO *out, int indent)
341 {
342     int i;
343     OSSL_DAY_TIME_BAND *band;
344     ASN1_INTEGER *big_val;
345     int64_t small_val;
346     OSSL_NAMED_DAY *nd;
347 
348     if (BIO_printf(out, "%*sPeriod:\n", indent, "") <= 0)
349         return 0;
350     if (p->timesOfDay) {
351         if (BIO_printf(out, "%*sDaytime bands:\n", indent + 4, "") <= 0)
352             return 0;
353         for (i = 0; i < sk_OSSL_DAY_TIME_BAND_num(p->timesOfDay); i++) {
354             band = sk_OSSL_DAY_TIME_BAND_value(p->timesOfDay, i);
355             if (BIO_printf(out, "%*s", indent + 8, "") <= 0)
356                 return 0;
357             if (!i2r_OSSL_DAY_TIME_BAND(method, band, out, indent + 8))
358                 return 0;
359             if (!BIO_puts(out, "\n"))
360                 return 0;
361         }
362     }
363     if (p->days) {
364         if (p->days->type == OSSL_TIME_SPEC_DAY_TYPE_INT) {
365             if (p->weeks != NULL) {
366                 if (BIO_printf(out, "%*sDays of the week: ", indent + 4, "") <= 0)
367                     return 0;
368             } else if (p->months != NULL) {
369                 if (BIO_printf(out, "%*sDays of the month: ", indent + 4, "") <= 0)
370                     return 0;
371             } else if (p->years != NULL) {
372                 if (BIO_printf(out, "%*sDays of the year: ", indent + 4, "") <= 0)
373                     return 0;
374             }
375         } else {
376             if (BIO_printf(out, "%*sDays: ", indent + 4, "") <= 0)
377                 return 0;
378         }
379 
380         switch (p->days->type) {
381         case (OSSL_TIME_SPEC_DAY_TYPE_INT):
382             for (i = 0; i < sk_ASN1_INTEGER_num(p->days->choice.intDay); i++) {
383                 big_val = sk_ASN1_INTEGER_value(p->days->choice.intDay, i);
384                 if (!ASN1_INTEGER_get_int64(&small_val, big_val))
385                     return 0;
386                 if (i > 0 && !BIO_puts(out, ", "))
387                     return 0;
388                 /* If weeks is defined, then print day of week by name. */
389                 if (p->weeks != NULL) {
390                     if (!print_int_day_of_week(out, small_val))
391                         return 0;
392                 } else if (BIO_printf(out, "%lld", (long long int)small_val) <= 0) {
393                     return 0;
394                 }
395             }
396             break;
397         case (OSSL_TIME_SPEC_DAY_TYPE_BIT):
398             if (!print_day_of_week(out, p->days->choice.bitDay))
399                 return 0;
400             break;
401         case (OSSL_TIME_SPEC_DAY_TYPE_DAY_OF):
402             switch (p->days->choice.dayOf->type) {
403             case (OSSL_TIME_SPEC_X_DAY_OF_FIRST):
404                 if (!BIO_puts(out, "FIRST "))
405                     return 0;
406                 nd = p->days->choice.dayOf->choice.first;
407                 break;
408             case (OSSL_TIME_SPEC_X_DAY_OF_SECOND):
409                 if (!BIO_puts(out, "SECOND "))
410                     return 0;
411                 nd = p->days->choice.dayOf->choice.second;
412                 break;
413             case (OSSL_TIME_SPEC_X_DAY_OF_THIRD):
414                 if (!BIO_puts(out, "THIRD "))
415                     return 0;
416                 nd = p->days->choice.dayOf->choice.third;
417                 break;
418             case (OSSL_TIME_SPEC_X_DAY_OF_FOURTH):
419                 if (!BIO_puts(out, "FOURTH "))
420                     return 0;
421                 nd = p->days->choice.dayOf->choice.fourth;
422                 break;
423             case (OSSL_TIME_SPEC_X_DAY_OF_FIFTH):
424                 if (!BIO_puts(out, "FIFTH "))
425                     return 0;
426                 nd = p->days->choice.dayOf->choice.fifth;
427                 break;
428             default:
429                 return 0;
430             }
431             switch (nd->type) {
432             case (OSSL_NAMED_DAY_TYPE_INT):
433                 if (!ASN1_INTEGER_get_int64(&small_val, nd->choice.intNamedDays))
434                     return 0;
435                 if (!print_int_named_day(out, small_val))
436                     return 0;
437                 break;
438             case (OSSL_NAMED_DAY_TYPE_BIT):
439                 if (!print_bit_named_day(out, nd->choice.bitNamedDays))
440                     return 0;
441                 break;
442             default:
443                 return 0;
444             }
445             break;
446         default:
447             return 0;
448         }
449         if (!BIO_puts(out, "\n"))
450             return 0;
451     }
452     if (p->weeks) {
453         if (p->weeks->type == OSSL_TIME_SPEC_WEEKS_TYPE_INT) {
454             if (p->months != NULL) {
455                 if (BIO_printf(out, "%*sWeeks of the month: ", indent + 4, "") <= 0)
456                     return 0;
457             } else if (p->years != NULL) {
458                 if (BIO_printf(out, "%*sWeeks of the year: ", indent + 4, "") <= 0)
459                     return 0;
460             }
461         } else {
462             if (BIO_printf(out, "%*sWeeks: ", indent + 4, "") <= 0)
463                 return 0;
464         }
465 
466         switch (p->weeks->type) {
467         case (OSSL_TIME_SPEC_WEEKS_TYPE_ALL):
468             if (!BIO_puts(out, "ALL"))
469                 return 0;
470             break;
471         case (OSSL_TIME_SPEC_WEEKS_TYPE_INT):
472             for (i = 0; i < sk_ASN1_INTEGER_num(p->weeks->choice.intWeek); i++) {
473                 big_val = sk_ASN1_INTEGER_value(p->weeks->choice.intWeek, i);
474                 if (!ASN1_INTEGER_get_int64(&small_val, big_val))
475                     return 0;
476                 if (i > 0 && !BIO_puts(out, ", "))
477                     return 0;
478                 if (!BIO_printf(out, "%lld", (long long int)small_val))
479                     return 0;
480             }
481             break;
482         case (OSSL_TIME_SPEC_WEEKS_TYPE_BIT):
483             if (!print_bit_week(out, p->weeks->choice.bitWeek))
484                 return 0;
485             break;
486         default:
487             return 0;
488         }
489         if (!BIO_puts(out, "\n"))
490             return 0;
491     }
492     if (p->months) {
493         if (BIO_printf(out, "%*sMonths: ", indent + 4, "") <= 0)
494             return 0;
495         switch (p->months->type) {
496         case (OSSL_TIME_SPEC_MONTH_TYPE_ALL):
497             if (!BIO_puts(out, "ALL"))
498                 return 0;
499             break;
500         case (OSSL_TIME_SPEC_MONTH_TYPE_INT):
501             for (i = 0; i < sk_ASN1_INTEGER_num(p->months->choice.intMonth); i++) {
502                 big_val = sk_ASN1_INTEGER_value(p->months->choice.intMonth, i);
503                 if (!ASN1_INTEGER_get_int64(&small_val, big_val))
504                     return 0;
505                 if (i > 0 && !BIO_puts(out, ", "))
506                     return 0;
507                 if (!print_int_month(out, small_val))
508                     return 0;
509             }
510             break;
511         case (OSSL_TIME_SPEC_MONTH_TYPE_BIT):
512             if (!print_bit_month(out, p->months->choice.bitMonth))
513                 return 0;
514             break;
515         default:
516             return 0;
517         }
518         if (!BIO_puts(out, "\n"))
519             return 0;
520     }
521     if (p->years) {
522         if (BIO_printf(out, "%*sYears: ", indent + 4, "") <= 0)
523             return 0;
524         for (i = 0; i < sk_ASN1_INTEGER_num(p->years); i++) {
525             big_val = sk_ASN1_INTEGER_value(p->years, i);
526             if (!ASN1_INTEGER_get_int64(&small_val, big_val))
527                 return 0;
528             if (i > 0 && !BIO_puts(out, ", "))
529                 return 0;
530             if (BIO_printf(out, "%04lld", (long long int)small_val) <= 0)
531                 return 0;
532         }
533     }
534     return 1;
535 }
536 
i2r_OSSL_TIME_SPEC_TIME(X509V3_EXT_METHOD * method,OSSL_TIME_SPEC_TIME * time,BIO * out,int indent)537 static int i2r_OSSL_TIME_SPEC_TIME(X509V3_EXT_METHOD *method,
538     OSSL_TIME_SPEC_TIME *time,
539     BIO *out, int indent)
540 {
541     OSSL_TIME_PERIOD *tp;
542     int i;
543 
544     switch (time->type) {
545     case (OSSL_TIME_SPEC_TIME_TYPE_ABSOLUTE):
546         if (BIO_printf(out, "%*sAbsolute: ", indent, "") <= 0)
547             return 0;
548         if (i2r_OSSL_TIME_SPEC_ABSOLUTE(method, time->choice.absolute, out, indent + 4) <= 0)
549             return 0;
550         return BIO_puts(out, "\n");
551     case (OSSL_TIME_SPEC_TIME_TYPE_PERIODIC):
552         if (BIO_printf(out, "%*sPeriodic:\n", indent, "") <= 0)
553             return 0;
554         for (i = 0; i < sk_OSSL_TIME_PERIOD_num(time->choice.periodic); i++) {
555             if (i > 0 && !BIO_puts(out, "\n"))
556                 return 0;
557             tp = sk_OSSL_TIME_PERIOD_value(time->choice.periodic, i);
558             if (!i2r_OSSL_PERIOD(method, tp, out, indent + 4))
559                 return 0;
560         }
561         return BIO_puts(out, "\n");
562     default:
563         return 0;
564     }
565     return 0;
566 }
567 
i2r_OSSL_TIME_SPEC(X509V3_EXT_METHOD * method,OSSL_TIME_SPEC * time,BIO * out,int indent)568 static int i2r_OSSL_TIME_SPEC(X509V3_EXT_METHOD *method,
569     OSSL_TIME_SPEC *time,
570     BIO *out, int indent)
571 {
572     int64_t tz;
573 
574     if (time->timeZone) {
575         if (ASN1_INTEGER_get_int64(&tz, time->timeZone) != 1)
576             return 0;
577         if (BIO_printf(out, "%*sTimezone: UTC%+03lld:00\n", indent, "", (long long int)tz) <= 0)
578             return 0;
579     }
580     if (time->notThisTime > 0) {
581         if (BIO_printf(out, "%*sNOT this time:\n", indent, "") <= 0)
582             return 0;
583     } else if (BIO_printf(out, "%*sTime:\n", indent, "") <= 0) {
584         return 0;
585     }
586     return i2r_OSSL_TIME_SPEC_TIME(method, time->time, out, indent + 4);
587 }
588 
589 const X509V3_EXT_METHOD ossl_v3_time_specification = {
590     NID_time_specification, X509V3_EXT_MULTILINE,
591     ASN1_ITEM_ref(OSSL_TIME_SPEC),
592     0, 0, 0, 0,
593     0, 0,
594     0,
595     0,
596     (X509V3_EXT_I2R)i2r_OSSL_TIME_SPEC,
597     NULL,
598     NULL
599 };
600