xref: /openssl/crypto/x509/v3_timespec.c (revision 70b17e5a)
1 /*
2  * Copyright 2024 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->minute && !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) > 0;
174 }
175 
i2r_OSSL_DAY_TIME_BAND(X509V3_EXT_METHOD * method,OSSL_DAY_TIME_BAND * band,BIO * out,int indent)176 static int i2r_OSSL_DAY_TIME_BAND(X509V3_EXT_METHOD *method,
177                                   OSSL_DAY_TIME_BAND *band,
178                                   BIO *out, int indent)
179 {
180     if (band->startDayTime) {
181         if (!i2r_OSSL_DAY_TIME(method, band->startDayTime, out, indent))
182             return 0;
183     } else if (!BIO_puts(out, "00:00:00")) {
184         return 0;
185     }
186     if (!BIO_puts(out, " - "))
187         return 0;
188     if (band->endDayTime) {
189         if (!i2r_OSSL_DAY_TIME(method, band->endDayTime, out, indent))
190             return 0;
191     } else if (!BIO_puts(out, "23:59:59")) {
192         return 0;
193     }
194     return 1;
195 }
196 
print_int_month(BIO * out,int64_t month)197 static int print_int_month(BIO *out, int64_t month)
198 {
199     switch (month) {
200     case (OSSL_TIME_SPEC_INT_MONTH_JAN):
201         return BIO_puts(out, "JAN");
202     case (OSSL_TIME_SPEC_INT_MONTH_FEB):
203         return BIO_puts(out, "FEB");
204     case (OSSL_TIME_SPEC_INT_MONTH_MAR):
205         return BIO_puts(out, "MAR");
206     case (OSSL_TIME_SPEC_INT_MONTH_APR):
207         return BIO_puts(out, "APR");
208     case (OSSL_TIME_SPEC_INT_MONTH_MAY):
209         return BIO_puts(out, "MAY");
210     case (OSSL_TIME_SPEC_INT_MONTH_JUN):
211         return BIO_puts(out, "JUN");
212     case (OSSL_TIME_SPEC_INT_MONTH_JUL):
213         return BIO_puts(out, "JUL");
214     case (OSSL_TIME_SPEC_INT_MONTH_AUG):
215         return BIO_puts(out, "AUG");
216     case (OSSL_TIME_SPEC_INT_MONTH_SEP):
217         return BIO_puts(out, "SEP");
218     case (OSSL_TIME_SPEC_INT_MONTH_OCT):
219         return BIO_puts(out, "OCT");
220     case (OSSL_TIME_SPEC_INT_MONTH_NOV):
221         return BIO_puts(out, "NOV");
222     case (OSSL_TIME_SPEC_INT_MONTH_DEC):
223         return BIO_puts(out, "DEC");
224     default:
225         return 0;
226     }
227     return 0;
228 }
229 
print_bit_month(BIO * out,ASN1_BIT_STRING * bs)230 static int print_bit_month(BIO *out, ASN1_BIT_STRING *bs)
231 {
232     int i = OSSL_TIME_SPEC_BIT_MONTH_JAN;
233     int j = 0;
234 
235     for (; i <= OSSL_TIME_SPEC_BIT_MONTH_DEC; i++) {
236         if (ASN1_BIT_STRING_get_bit(bs, i)) {
237             if (j > 0 && !BIO_puts(out, ", "))
238                 return 0;
239             j++;
240             if (!BIO_puts(out, MONTH_NAMES[i]))
241                 return 0;
242         }
243     }
244     return 1;
245 }
246 
247 /*
248  * It might seem like you could just print the bits of the string numerically,
249  * but the fifth bit has the special meaning of "the final week" imputed to it
250  * by the text of ITU-T Recommendation X.520.
251  */
print_bit_week(BIO * out,ASN1_BIT_STRING * bs)252 static int print_bit_week(BIO *out, ASN1_BIT_STRING *bs)
253 {
254     int i = OSSL_TIME_SPEC_BIT_WEEKS_1;
255     int j = 0;
256 
257     for (; i <= OSSL_TIME_SPEC_BIT_WEEKS_5; i++) {
258         if (ASN1_BIT_STRING_get_bit(bs, i)) {
259             if (j > 0 && !BIO_puts(out, ", "))
260                 return 0;
261             j++;
262             if (!BIO_puts(out, WEEK_NAMES[i]))
263                 return 0;
264         }
265     }
266     return 1;
267 }
268 
print_day_of_week(BIO * out,ASN1_BIT_STRING * bs)269 static int print_day_of_week(BIO *out, ASN1_BIT_STRING *bs)
270 {
271     int i = OSSL_TIME_SPEC_DAY_BIT_SUN;
272     int j = 0;
273 
274     for (; i <= OSSL_TIME_SPEC_DAY_BIT_SAT; i++) {
275         if (ASN1_BIT_STRING_get_bit(bs, i)) {
276             if (j > 0 && !BIO_puts(out, ", "))
277                 return 0;
278             j++;
279             if (!BIO_puts(out, WEEKDAY_NAMES[i]))
280                 return 0;
281         }
282     }
283     return 1;
284 }
285 
print_int_day_of_week(BIO * out,int64_t dow)286 static int print_int_day_of_week(BIO *out, int64_t dow)
287 {
288     switch (dow) {
289     case (OSSL_TIME_SPEC_DAY_INT_SUN):
290         return BIO_puts(out, "SUN");
291     case (OSSL_TIME_SPEC_DAY_INT_MON):
292         return BIO_puts(out, "MON");
293     case (OSSL_TIME_SPEC_DAY_INT_TUE):
294         return BIO_puts(out, "TUE");
295     case (OSSL_TIME_SPEC_DAY_INT_WED):
296         return BIO_puts(out, "WED");
297     case (OSSL_TIME_SPEC_DAY_INT_THU):
298         return BIO_puts(out, "THU");
299     case (OSSL_TIME_SPEC_DAY_INT_FRI):
300         return BIO_puts(out, "FRI");
301     case (OSSL_TIME_SPEC_DAY_INT_SAT):
302         return BIO_puts(out, "SAT");
303     default:
304         return 0;
305     }
306     return 0;
307 }
308 
print_int_named_day(BIO * out,int64_t nd)309 static int print_int_named_day(BIO *out, int64_t nd)
310 {
311     switch (nd) {
312     case (OSSL_NAMED_DAY_INT_SUN):
313         return BIO_puts(out, "SUN");
314     case (OSSL_NAMED_DAY_INT_MON):
315         return BIO_puts(out, "MON");
316     case (OSSL_NAMED_DAY_INT_TUE):
317         return BIO_puts(out, "TUE");
318     case (OSSL_NAMED_DAY_INT_WED):
319         return BIO_puts(out, "WED");
320     case (OSSL_NAMED_DAY_INT_THU):
321         return BIO_puts(out, "THU");
322     case (OSSL_NAMED_DAY_INT_FRI):
323         return BIO_puts(out, "FRI");
324     case (OSSL_NAMED_DAY_INT_SAT):
325         return BIO_puts(out, "SAT");
326     default:
327         return 0;
328     }
329     return 0;
330 }
331 
print_bit_named_day(BIO * out,ASN1_BIT_STRING * bs)332 static int print_bit_named_day(BIO *out, ASN1_BIT_STRING *bs)
333 {
334     return print_day_of_week(out, bs);
335 }
336 
i2r_OSSL_PERIOD(X509V3_EXT_METHOD * method,OSSL_TIME_PERIOD * p,BIO * out,int indent)337 static int i2r_OSSL_PERIOD(X509V3_EXT_METHOD *method,
338                            OSSL_TIME_PERIOD *p,
339                            BIO *out, int indent)
340 {
341     int i;
342     OSSL_DAY_TIME_BAND *band;
343     ASN1_INTEGER *big_val;
344     int64_t small_val;
345     OSSL_NAMED_DAY *nd;
346 
347     if (BIO_printf(out, "%*sPeriod:\n", indent, "") <= 0)
348         return 0;
349     if (p->timesOfDay) {
350         if (BIO_printf(out, "%*sDaytime bands:\n", indent + 4, "") <= 0)
351             return 0;
352         for (i = 0; i < sk_OSSL_DAY_TIME_BAND_num(p->timesOfDay); i++) {
353             band = sk_OSSL_DAY_TIME_BAND_value(p->timesOfDay, i);
354             if (BIO_printf(out, "%*s", indent + 8, "") <= 0)
355                 return 0;
356             if (!i2r_OSSL_DAY_TIME_BAND(method, band, out, indent + 8))
357                 return 0;
358             if (!BIO_puts(out, "\n"))
359                 return 0;
360         }
361     }
362     if (p->days) {
363         if (p->days->type == OSSL_TIME_SPEC_DAY_TYPE_INT) {
364             if (p->weeks != NULL) {
365                 if (BIO_printf(out, "%*sDays of the week: ", indent + 4, "") <= 0)
366                     return 0;
367             } else if (p->months != NULL) {
368                 if (BIO_printf(out, "%*sDays of the month: ", indent + 4, "") <= 0)
369                     return 0;
370             } else if (p->years != NULL) {
371                 if (BIO_printf(out, "%*sDays of the year: ", indent + 4, "") <= 0)
372                     return 0;
373             }
374         } else {
375             if (BIO_printf(out, "%*sDays: ", indent + 4, "") <= 0)
376                 return 0;
377         }
378 
379         switch (p->days->type) {
380         case (OSSL_TIME_SPEC_DAY_TYPE_INT):
381             for (i = 0; i < sk_ASN1_INTEGER_num(p->days->choice.intDay); i++) {
382                 big_val = sk_ASN1_INTEGER_value(p->days->choice.intDay, i);
383                 if (!ASN1_INTEGER_get_int64(&small_val, big_val))
384                     return 0;
385                 if (i > 0 && !BIO_puts(out, ", "))
386                     return 0;
387                 /* If weeks is defined, then print day of week by name. */
388                 if (p->weeks != NULL) {
389                     if (!print_int_day_of_week(out, small_val))
390                         return 0;
391                 } else if (BIO_printf(out, "%lld", (long long int)small_val) <= 0) {
392                     return 0;
393                 }
394             }
395             break;
396         case (OSSL_TIME_SPEC_DAY_TYPE_BIT):
397             if (!print_day_of_week(out, p->days->choice.bitDay))
398                 return 0;
399             break;
400         case (OSSL_TIME_SPEC_DAY_TYPE_DAY_OF):
401             switch (p->days->choice.dayOf->type) {
402             case (OSSL_TIME_SPEC_X_DAY_OF_FIRST):
403                 if (!BIO_puts(out, "FIRST "))
404                     return 0;
405                 nd = p->days->choice.dayOf->choice.first;
406                 break;
407             case (OSSL_TIME_SPEC_X_DAY_OF_SECOND):
408                 if (!BIO_puts(out, "SECOND "))
409                     return 0;
410                 nd = p->days->choice.dayOf->choice.second;
411                 break;
412             case (OSSL_TIME_SPEC_X_DAY_OF_THIRD):
413                 if (!BIO_puts(out, "THIRD "))
414                     return 0;
415                 nd = p->days->choice.dayOf->choice.third;
416                 break;
417             case (OSSL_TIME_SPEC_X_DAY_OF_FOURTH):
418                 if (!BIO_puts(out, "FOURTH "))
419                     return 0;
420                 nd = p->days->choice.dayOf->choice.fourth;
421                 break;
422             case (OSSL_TIME_SPEC_X_DAY_OF_FIFTH):
423                 if (!BIO_puts(out, "FIFTH "))
424                     return 0;
425                 nd = p->days->choice.dayOf->choice.fifth;
426                 break;
427             default:
428                 return 0;
429             }
430             switch (nd->type) {
431             case (OSSL_NAMED_DAY_TYPE_INT):
432                 if (!ASN1_INTEGER_get_int64(&small_val, nd->choice.intNamedDays))
433                     return 0;
434                 if (!print_int_named_day(out, small_val))
435                     return 0;
436                 break;
437             case (OSSL_NAMED_DAY_TYPE_BIT):
438                 if (!print_bit_named_day(out, nd->choice.bitNamedDays))
439                     return 0;
440                 break;
441             default:
442                 return 0;
443             }
444             break;
445         default:
446             return 0;
447         }
448         if (!BIO_puts(out, "\n"))
449             return 0;
450     }
451     if (p->weeks) {
452         if (p->weeks->type == OSSL_TIME_SPEC_WEEKS_TYPE_INT) {
453             if (p->months != NULL) {
454                 if (BIO_printf(out, "%*sWeeks of the month: ", indent + 4, "") <= 0)
455                     return 0;
456             } else if (p->years != NULL) {
457                 if (BIO_printf(out, "%*sWeeks of the year: ", indent + 4, "") <= 0)
458                     return 0;
459             }
460         } else {
461             if (BIO_printf(out, "%*sWeeks: ", indent + 4, "") <= 0)
462                 return 0;
463         }
464 
465         switch (p->weeks->type) {
466         case (OSSL_TIME_SPEC_WEEKS_TYPE_ALL):
467             if (!BIO_puts(out, "ALL"))
468                 return 0;
469             break;
470         case (OSSL_TIME_SPEC_WEEKS_TYPE_INT):
471             for (i = 0; i < sk_ASN1_INTEGER_num(p->weeks->choice.intWeek); i++) {
472                 big_val = sk_ASN1_INTEGER_value(p->weeks->choice.intWeek, i);
473                 if (!ASN1_INTEGER_get_int64(&small_val, big_val))
474                     return 0;
475                 if (i > 0 && !BIO_puts(out, ", "))
476                     return 0;
477                 if (!BIO_printf(out, "%lld", (long long int)small_val))
478                     return 0;
479             }
480             break;
481         case (OSSL_TIME_SPEC_WEEKS_TYPE_BIT):
482             if (!print_bit_week(out, p->weeks->choice.bitWeek))
483                 return 0;
484             break;
485         default:
486             return 0;
487         }
488         if (!BIO_puts(out, "\n"))
489             return 0;
490     }
491     if (p->months) {
492         if (BIO_printf(out, "%*sMonths: ", indent + 4, "") <= 0)
493             return 0;
494         switch (p->months->type) {
495         case (OSSL_TIME_SPEC_MONTH_TYPE_ALL):
496             if (!BIO_puts(out, "ALL"))
497                 return 0;
498             break;
499         case (OSSL_TIME_SPEC_MONTH_TYPE_INT):
500             for (i = 0; i < sk_ASN1_INTEGER_num(p->months->choice.intMonth); i++) {
501                 big_val = sk_ASN1_INTEGER_value(p->months->choice.intMonth, i);
502                 if (!ASN1_INTEGER_get_int64(&small_val, big_val))
503                     return 0;
504                 if (i > 0 && !BIO_puts(out, ", "))
505                     return 0;
506                 if (!print_int_month(out, small_val))
507                     return 0;
508             }
509             break;
510         case (OSSL_TIME_SPEC_MONTH_TYPE_BIT):
511             if (!print_bit_month(out, p->months->choice.bitMonth))
512                 return 0;
513             break;
514         default:
515             return 0;
516         }
517         if (!BIO_puts(out, "\n"))
518             return 0;
519     }
520     if (p->years) {
521         if (BIO_printf(out, "%*sYears: ", indent + 4, "") <= 0)
522             return 0;
523         for (i = 0; i < sk_ASN1_INTEGER_num(p->years); i++) {
524             big_val = sk_ASN1_INTEGER_value(p->years, i);
525             if (!ASN1_INTEGER_get_int64(&small_val, big_val))
526                 return 0;
527             if (i > 0 && !BIO_puts(out, ", "))
528                 return 0;
529             if (BIO_printf(out, "%04lld", (long long int)small_val) <= 0)
530                 return 0;
531         }
532     }
533     return 1;
534 }
535 
i2r_OSSL_TIME_SPEC_TIME(X509V3_EXT_METHOD * method,OSSL_TIME_SPEC_TIME * time,BIO * out,int indent)536 static int i2r_OSSL_TIME_SPEC_TIME(X509V3_EXT_METHOD *method,
537                                    OSSL_TIME_SPEC_TIME *time,
538                                    BIO *out, int indent)
539 {
540     OSSL_TIME_PERIOD *tp;
541     int i;
542 
543     switch (time->type) {
544     case (OSSL_TIME_SPEC_TIME_TYPE_ABSOLUTE):
545         if (BIO_printf(out, "%*sAbsolute: ", indent, "") <= 0)
546             return 0;
547         if (i2r_OSSL_TIME_SPEC_ABSOLUTE(method, time->choice.absolute, out, indent + 4) <= 0)
548             return 0;
549         return BIO_puts(out, "\n");
550     case (OSSL_TIME_SPEC_TIME_TYPE_PERIODIC):
551         if (BIO_printf(out, "%*sPeriodic:\n", indent, "") <= 0)
552             return 0;
553         for (i = 0; i < sk_OSSL_TIME_PERIOD_num(time->choice.periodic); i++) {
554             if (i > 0 && !BIO_puts(out, "\n"))
555                 return 0;
556             tp = sk_OSSL_TIME_PERIOD_value(time->choice.periodic, i);
557             if (!i2r_OSSL_PERIOD(method, tp, out, indent + 4))
558                 return 0;
559         }
560         return BIO_puts(out, "\n");
561     default:
562         return 0;
563     }
564     return 0;
565 }
566 
i2r_OSSL_TIME_SPEC(X509V3_EXT_METHOD * method,OSSL_TIME_SPEC * time,BIO * out,int indent)567 static int i2r_OSSL_TIME_SPEC(X509V3_EXT_METHOD *method,
568                               OSSL_TIME_SPEC *time,
569                               BIO *out, int indent)
570 {
571     int64_t tz;
572 
573     if (time->timeZone) {
574         if (ASN1_INTEGER_get_int64(&tz, time->timeZone) != 1)
575             return 0;
576         if (BIO_printf(out, "%*sTimezone: UTC%+03lld:00\n", indent, "", (long long int)tz) <= 0)
577             return 0;
578     }
579     if (time->notThisTime > 0) {
580         if (BIO_printf(out, "%*sNOT this time:\n", indent, "") <= 0)
581             return 0;
582     } else if (BIO_printf(out, "%*sTime:\n", indent, "") <= 0) {
583         return 0;
584     }
585     return i2r_OSSL_TIME_SPEC_TIME(method, time->time, out, indent + 4);
586 }
587 
588 const X509V3_EXT_METHOD ossl_v3_time_specification = {
589     NID_time_specification, X509V3_EXT_MULTILINE,
590     ASN1_ITEM_ref(OSSL_TIME_SPEC),
591     0, 0, 0, 0,
592     0, 0,
593     0,
594     0,
595     (X509V3_EXT_I2R)i2r_OSSL_TIME_SPEC,
596     NULL,
597     NULL
598 };
599