Coverage Report

Created: 2026-08-14 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/x509/time.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2003-2016 Free Software Foundation, Inc.
3
 * Copyright (C) 2016 Red Hat, Inc.
4
 *
5
 * Author: Nikos Mavrogiannopoulos
6
 *
7
 * This file is part of GnuTLS.
8
 *
9
 * The GnuTLS is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public License
11
 * as published by the Free Software Foundation; either version 2.1 of
12
 * the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
21
 *
22
 */
23
24
#include "gnutls_int.h"
25
#include <libtasn1.h>
26
#include "datum.h"
27
#include "global.h"
28
#include "errors.h"
29
#include "str.h"
30
#include "x509.h"
31
#include "num.h"
32
#include "x509_b64.h"
33
#include "x509_int.h"
34
#include "extras/hex.h"
35
#include "common.h"
36
#include <c-ctype.h>
37
38
/* TIME functions
39
 * Conversions between generalized or UTC time to time_t
40
 *
41
 */
42
43
/* This is an emulation of the struct tm.
44
 * Since we do not use libc's functions, we don't need to
45
 * depend on the libc structure.
46
 */
47
typedef struct fake_tm {
48
  int tm_mon;
49
  int tm_year; /* FULL year - ie 1971 */
50
  int tm_mday;
51
  int tm_hour;
52
  int tm_min;
53
  int tm_sec;
54
} fake_tm;
55
56
/* The mktime_utc function is due to Russ Allbery (rra@stanford.edu),
57
 * who placed it under public domain:
58
 */
59
60
/* The number of days in each month.
61
 */
62
static const int MONTHDAYS[] = {
63
  31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
64
};
65
66
/* Whether a given year is a leap year. */
67
#define ISLEAP(year) \
68
0
  (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0))
69
70
/* Given a struct tm representing a calendar time in UTC, convert it to
71
 * seconds since epoch.  Returns (time_t) -1 if the time is not
72
 * convertible.  Note that this function does not canonicalize the provided
73
 * struct tm, nor does it allow out of range values or years before 1970.
74
 */
75
static time_t mktime_utc(const struct fake_tm *tm)
76
0
{
77
0
  time_t result = 0;
78
0
  int i;
79
80
  /* We do allow some ill-formed dates, but we don't do anything special
81
   * with them and our callers really shouldn't pass them to us.  Do
82
   * explicitly disallow the ones that would cause invalid array accesses
83
   * or other algorithm problems.
84
   */
85
0
  if (tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 1970)
86
0
    return (time_t)-1;
87
88
  /* Check for "obvious" mistakes in dates */
89
0
  if (tm->tm_sec > 60 || tm->tm_min > 59 || tm->tm_mday > 31 ||
90
0
      tm->tm_mday < 1 || tm->tm_hour > 23)
91
0
    return (time_t)-1;
92
93
  /* Convert to a time_t.
94
   */
95
0
  for (i = 1970; i < tm->tm_year; i++)
96
0
    result += 365 + ISLEAP(i);
97
0
  for (i = 0; i < tm->tm_mon; i++)
98
0
    result += MONTHDAYS[i];
99
0
  if (tm->tm_mon > 1 && ISLEAP(tm->tm_year))
100
0
    result++;
101
0
  result = 24 * (result + tm->tm_mday - 1) + tm->tm_hour;
102
0
  result = 60 * result + tm->tm_min;
103
0
  result = 60 * result + tm->tm_sec;
104
0
  return result;
105
0
}
106
107
/* this one will parse dates of the form:
108
 * month|day|hour|minute|sec* (2 chars each)
109
 * and year is given. Returns a time_t date.
110
 */
111
static time_t time2gtime(const char *ttime, int year)
112
0
{
113
0
  char xx[4];
114
0
  struct fake_tm etime;
115
116
0
  if (strlen(ttime) < 8) {
117
0
    gnutls_assert();
118
0
    return (time_t)-1;
119
0
  }
120
121
0
  etime.tm_year = year;
122
123
  /* In order to work with 32 bit
124
   * time_t.
125
   */
126
0
  if (sizeof(time_t) <= 4 && etime.tm_year >= 2038)
127
0
    return (time_t)2145914603; /* 2037-12-31 23:23:23 */
128
129
0
  if (etime.tm_year < 1970)
130
0
    return (time_t)0;
131
132
0
  xx[2] = 0;
133
134
  /* get the month
135
   */
136
0
  memcpy(xx, ttime, 2); /* month */
137
0
  etime.tm_mon = atoi(xx) - 1;
138
0
  ttime += 2;
139
140
  /* get the day
141
   */
142
0
  memcpy(xx, ttime, 2); /* day */
143
0
  etime.tm_mday = atoi(xx);
144
0
  ttime += 2;
145
146
  /* get the hour
147
   */
148
0
  memcpy(xx, ttime, 2); /* hour */
149
0
  etime.tm_hour = atoi(xx);
150
0
  ttime += 2;
151
152
  /* get the minutes
153
   */
154
0
  memcpy(xx, ttime, 2); /* minutes */
155
0
  etime.tm_min = atoi(xx);
156
0
  ttime += 2;
157
158
0
  if (strlen(ttime) >= 2) {
159
0
    memcpy(xx, ttime, 2);
160
0
    etime.tm_sec = atoi(xx);
161
0
  } else
162
0
    etime.tm_sec = 0;
163
164
0
  return mktime_utc(&etime);
165
0
}
166
167
/* returns a time_t value that contains the given time.
168
 * The given time is expressed as:
169
 * YEAR(2)|MONTH(2)|DAY(2)|HOUR(2)|MIN(2)|SEC(2)*
170
 *
171
 * (seconds are optional)
172
 */
173
time_t _gnutls_utcTime2gtime(const char *ttime)
174
0
{
175
0
  char xx[3];
176
0
  int year, i;
177
0
  int len = strlen(ttime);
178
179
0
  if (len < 10) {
180
0
    gnutls_assert();
181
0
    return (time_t)-1;
182
0
  }
183
0
#ifdef STRICT_DER_TIME
184
  /* Make sure everything else is digits. */
185
0
  for (i = 0; i < len - 1; i++) {
186
0
    if (c_isdigit(ttime[i]))
187
0
      continue;
188
0
    return gnutls_assert_val((time_t)-1);
189
0
  }
190
0
#endif
191
0
  xx[2] = 0;
192
193
  /* get the year
194
   */
195
0
  memcpy(xx, ttime, 2); /* year */
196
0
  year = atoi(xx);
197
0
  ttime += 2;
198
199
0
  if (year > 49)
200
0
    year += 1900;
201
0
  else
202
0
    year += 2000;
203
204
0
  return time2gtime(ttime, year);
205
0
}
206
207
/* returns a time_t value that contains the given time.
208
 * The given time is expressed as:
209
 * YEAR(4)|MONTH(2)|DAY(2)|HOUR(2)|MIN(2)|SEC(2)*
210
 */
211
time_t _gnutls_x509_generalTime2gtime(const char *ttime)
212
0
{
213
0
  char xx[5];
214
0
  int year;
215
216
0
  if (strlen(ttime) < 12) {
217
0
    gnutls_assert();
218
0
    return (time_t)-1;
219
0
  }
220
221
0
  if (strchr(ttime, 'Z') == NULL) {
222
0
    gnutls_assert();
223
    /* required to be in GMT */
224
0
    return (time_t)-1;
225
0
  }
226
227
0
  if (strchr(ttime, '.') != NULL) {
228
0
    gnutls_assert();
229
    /* no fractional seconds allowed */
230
0
    return (time_t)-1;
231
0
  }
232
0
  xx[4] = 0;
233
234
  /* get the year
235
   */
236
0
  memcpy(xx, ttime, 4); /* year */
237
0
  year = atoi(xx);
238
0
  ttime += 4;
239
240
0
  return time2gtime(ttime, year);
241
0
}
242
243
#pragma GCC diagnostic push
244
#pragma GCC diagnostic ignored "-Wformat-y2k"
245
/* tag will contain ASN1_TAG_UTCTime or ASN1_TAG_GENERALIZEDTime */
246
static int gtime_to_suitable_time(time_t gtime, char *str_time,
247
          size_t str_time_size, unsigned *tag)
248
0
{
249
0
  size_t ret;
250
0
  struct tm _tm;
251
252
0
  if (gtime == (time_t)-1
253
0
#if SIZEOF_LONG == 8
254
0
      || gtime >= 253402210800
255
0
#endif
256
0
  ) {
257
0
    if (tag)
258
0
      *tag = ASN1_TAG_GENERALIZEDTime;
259
0
    snprintf(str_time, str_time_size, "99991231235959Z");
260
0
    return 0;
261
0
  }
262
263
0
  if (!gmtime_r(&gtime, &_tm)) {
264
0
    gnutls_assert();
265
0
    return GNUTLS_E_INTERNAL_ERROR;
266
0
  }
267
268
0
  if (_tm.tm_year >= 150) {
269
0
    if (tag)
270
0
      *tag = ASN1_TAG_GENERALIZEDTime;
271
0
    ret = strftime(str_time, str_time_size, "%Y%m%d%H%M%SZ", &_tm);
272
0
  } else {
273
0
    if (tag)
274
0
      *tag = ASN1_TAG_UTCTime;
275
0
    ret = strftime(str_time, str_time_size, "%y%m%d%H%M%SZ", &_tm);
276
0
  }
277
278
0
  if (!ret) {
279
0
    gnutls_assert();
280
0
    return GNUTLS_E_SHORT_MEMORY_BUFFER;
281
0
  }
282
283
0
  return 0;
284
0
}
285
286
#pragma GCC diagnostic pop
287
288
static int gtime_to_generalTime(time_t gtime, char *str_time,
289
        size_t str_time_size)
290
0
{
291
0
  size_t ret;
292
0
  struct tm _tm;
293
294
0
  if (gtime == (time_t)-1
295
0
#if SIZEOF_LONG == 8
296
0
      || gtime >= 253402210800
297
0
#endif
298
0
  ) {
299
0
    snprintf(str_time, str_time_size, "99991231235959Z");
300
0
    return 0;
301
0
  }
302
303
0
  if (!gmtime_r(&gtime, &_tm)) {
304
0
    gnutls_assert();
305
0
    return GNUTLS_E_INTERNAL_ERROR;
306
0
  }
307
308
0
  ret = strftime(str_time, str_time_size, "%Y%m%d%H%M%SZ", &_tm);
309
0
  if (!ret) {
310
0
    gnutls_assert();
311
0
    return GNUTLS_E_SHORT_MEMORY_BUFFER;
312
0
  }
313
314
0
  return 0;
315
0
}
316
317
/* Extracts the time in time_t from the asn1_node given. When should
318
 * be something like "tbsCertList.thisUpdate".
319
 */
320
#define MAX_TIME 64
321
time_t _gnutls_x509_get_time(asn1_node c2, const char *where, int force_general)
322
0
{
323
0
  char ttime[MAX_TIME];
324
0
  char name[128];
325
0
  time_t c_time = (time_t)-1;
326
0
  int len, result;
327
328
0
  len = sizeof(ttime) - 1;
329
0
  result = asn1_read_value(c2, where, ttime, &len);
330
0
  if (result != ASN1_SUCCESS) {
331
0
    gnutls_assert();
332
0
    return (time_t)(-1);
333
0
  }
334
335
0
  if (force_general != 0) {
336
0
    c_time = _gnutls_x509_generalTime2gtime(ttime);
337
0
  } else {
338
0
    _gnutls_str_cpy(name, sizeof(name), where);
339
340
    /* choice */
341
0
    if (streq(ttime, "generalTime")) {
342
0
      if (name[0] == 0)
343
0
        _gnutls_str_cpy(name, sizeof(name),
344
0
            "generalTime");
345
0
      else
346
0
        _gnutls_str_cat(name, sizeof(name),
347
0
            ".generalTime");
348
0
      len = sizeof(ttime) - 1;
349
0
      result = asn1_read_value(c2, name, ttime, &len);
350
0
      if (result == ASN1_SUCCESS)
351
0
        c_time = _gnutls_x509_generalTime2gtime(ttime);
352
0
    } else { /* UTCTIME */
353
0
      if (name[0] == 0)
354
0
        _gnutls_str_cpy(name, sizeof(name), "utcTime");
355
0
      else
356
0
        _gnutls_str_cat(name, sizeof(name), ".utcTime");
357
0
      len = sizeof(ttime) - 1;
358
0
      result = asn1_read_value(c2, name, ttime, &len);
359
0
      if (result == ASN1_SUCCESS)
360
0
        c_time = _gnutls_utcTime2gtime(ttime);
361
0
    }
362
363
    /* We cannot handle dates after 2031 in 32 bit machines.
364
     * a time_t of 64bits has to be used.
365
     */
366
0
    if (result != ASN1_SUCCESS) {
367
0
      gnutls_assert();
368
0
      return (time_t)(-1);
369
0
    }
370
0
  }
371
372
0
  return c_time;
373
0
}
374
375
/* Sets the time in time_t in the asn1_node given. Where should
376
 * be something like "tbsCertList.thisUpdate".
377
 */
378
int _gnutls_x509_set_time(asn1_node c2, const char *where, time_t tim,
379
        int force_general)
380
0
{
381
0
  char str_time[MAX_TIME];
382
0
  char name[128];
383
0
  int result, len;
384
0
  unsigned tag;
385
386
0
  if (force_general != 0) {
387
0
    result = gtime_to_generalTime(tim, str_time, sizeof(str_time));
388
0
    if (result < 0)
389
0
      return gnutls_assert_val(result);
390
0
    len = strlen(str_time);
391
0
    result = asn1_write_value(c2, where, str_time, len);
392
0
    if (result != ASN1_SUCCESS)
393
0
      return gnutls_assert_val(_gnutls_asn2err(result));
394
395
0
    return 0;
396
0
  }
397
398
0
  result = gtime_to_suitable_time(tim, str_time, sizeof(str_time), &tag);
399
0
  if (result < 0) {
400
0
    gnutls_assert();
401
0
    return result;
402
0
  }
403
404
0
  _gnutls_str_cpy(name, sizeof(name), where);
405
0
  if (tag == ASN1_TAG_UTCTime) {
406
0
    if ((result = asn1_write_value(c2, where, "utcTime", 1)) !=
407
0
        ASN1_SUCCESS) {
408
0
      gnutls_assert();
409
0
      return _gnutls_asn2err(result);
410
0
    }
411
0
    _gnutls_str_cat(name, sizeof(name), ".utcTime");
412
0
  } else {
413
0
    if ((result = asn1_write_value(c2, where, "generalTime", 1)) !=
414
0
        ASN1_SUCCESS) {
415
0
      gnutls_assert();
416
0
      return _gnutls_asn2err(result);
417
0
    }
418
0
    _gnutls_str_cat(name, sizeof(name), ".generalTime");
419
0
  }
420
421
0
  len = strlen(str_time);
422
0
  result = asn1_write_value(c2, name, str_time, len);
423
0
  if (result != ASN1_SUCCESS) {
424
0
    gnutls_assert();
425
0
    return _gnutls_asn2err(result);
426
0
  }
427
428
0
  return 0;
429
0
}
430
431
/* This will set a DER encoded Time element. To be used in fields
432
 * which are of the ANY.
433
 */
434
int _gnutls_x509_set_raw_time(asn1_node c2, const char *where, time_t tim)
435
0
{
436
0
  char str_time[MAX_TIME];
437
0
  uint8_t buf[128];
438
0
  int result, len, der_len;
439
0
  unsigned tag;
440
441
0
  result = gtime_to_suitable_time(tim, str_time, sizeof(str_time), &tag);
442
0
  if (result < 0)
443
0
    return gnutls_assert_val(result);
444
0
  len = strlen(str_time);
445
446
0
  buf[0] = tag;
447
0
  asn1_length_der(len, buf + 1, &der_len);
448
449
0
  if ((unsigned)len > sizeof(buf) - der_len - 1) {
450
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
451
0
  }
452
453
0
  memcpy(buf + 1 + der_len, str_time, len);
454
455
0
  result = asn1_write_value(c2, where, buf, len + 1 + der_len);
456
0
  if (result != ASN1_SUCCESS)
457
0
    return gnutls_assert_val(_gnutls_asn2err(result));
458
0
  return 0;
459
0
}