Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/x509/time.c
Line
Count
Source (jump to first uncovered line)
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
/*
71
 **  Given a struct tm representing a calendar time in UTC, convert it to
72
 **  seconds since epoch.  Returns (time_t) -1 if the time is not
73
 **  convertible.  Note that this function does not canonicalize the provided
74
 **  struct tm, nor does it allow out of range values or years before 1970.
75
 */
76
static time_t mktime_utc(const struct fake_tm *tm)
77
0
{
78
0
  time_t result = 0;
79
0
  int i;
80
81
  /* We do allow some ill-formed dates, but we don't do anything special
82
 * with them and our callers really shouldn't pass them to us.  Do
83
 * explicitly disallow the ones that would cause invalid array accesses
84
 * or other algorithm problems.
85
 */
86
0
  if (tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 1970)
87
0
    return (time_t)-1;
88
89
  /* Check for "obvious" mistakes in dates */
90
0
  if (tm->tm_sec > 60 || tm->tm_min > 59 || tm->tm_mday > 31 ||
91
0
      tm->tm_mday < 1 || tm->tm_hour > 23)
92
0
    return (time_t)-1;
93
94
  /* Convert to a time_t.
95
 */
96
0
  for (i = 1970; i < tm->tm_year; i++)
97
0
    result += 365 + ISLEAP(i);
98
0
  for (i = 0; i < tm->tm_mon; i++)
99
0
    result += MONTHDAYS[i];
100
0
  if (tm->tm_mon > 1 && ISLEAP(tm->tm_year))
101
0
    result++;
102
0
  result = 24 * (result + tm->tm_mday - 1) + tm->tm_hour;
103
0
  result = 60 * result + tm->tm_min;
104
0
  result = 60 * result + tm->tm_sec;
105
0
  return result;
106
0
}
107
108
/* this one will parse dates of the form:
109
 * month|day|hour|minute|sec* (2 chars each)
110
 * and year is given. Returns a time_t date.
111
 */
112
static time_t time2gtime(const char *ttime, int year)
113
0
{
114
0
  char xx[4];
115
0
  struct fake_tm etime;
116
117
0
  if (strlen(ttime) < 8) {
118
0
    gnutls_assert();
119
0
    return (time_t)-1;
120
0
  }
121
122
0
  etime.tm_year = year;
123
124
  /* In order to work with 32 bit
125
   * time_t.
126
   */
127
0
  if (sizeof(time_t) <= 4 && etime.tm_year >= 2038)
128
0
    return (time_t)2145914603; /* 2037-12-31 23:23:23 */
129
130
0
  if (etime.tm_year < 1970)
131
0
    return (time_t)0;
132
133
0
  xx[2] = 0;
134
135
  /* get the month
136
 */
137
0
  memcpy(xx, ttime, 2); /* month */
138
0
  etime.tm_mon = atoi(xx) - 1;
139
0
  ttime += 2;
140
141
  /* get the day
142
 */
143
0
  memcpy(xx, ttime, 2); /* day */
144
0
  etime.tm_mday = atoi(xx);
145
0
  ttime += 2;
146
147
  /* get the hour
148
 */
149
0
  memcpy(xx, ttime, 2); /* hour */
150
0
  etime.tm_hour = atoi(xx);
151
0
  ttime += 2;
152
153
  /* get the minutes
154
 */
155
0
  memcpy(xx, ttime, 2); /* minutes */
156
0
  etime.tm_min = atoi(xx);
157
0
  ttime += 2;
158
159
0
  if (strlen(ttime) >= 2) {
160
0
    memcpy(xx, ttime, 2);
161
0
    etime.tm_sec = atoi(xx);
162
0
  } else
163
0
    etime.tm_sec = 0;
164
165
0
  return mktime_utc(&etime);
166
0
}
167
168
/* returns a time_t value that contains the given time.
169
 * The given time is expressed as:
170
 * YEAR(2)|MONTH(2)|DAY(2)|HOUR(2)|MIN(2)|SEC(2)*
171
 *
172
 * (seconds are optional)
173
 */
174
time_t _gnutls_utcTime2gtime(const char *ttime)
175
0
{
176
0
  char xx[3];
177
0
  int year, i;
178
0
  int len = strlen(ttime);
179
180
0
  if (len < 10) {
181
0
    gnutls_assert();
182
0
    return (time_t)-1;
183
0
  }
184
0
#ifdef STRICT_DER_TIME
185
  /* Make sure everything else is digits. */
186
0
  for (i = 0; i < len - 1; i++) {
187
0
    if (c_isdigit(ttime[i]))
188
0
      continue;
189
0
    return gnutls_assert_val((time_t)-1);
190
0
  }
191
0
#endif
192
0
  xx[2] = 0;
193
194
  /* get the year
195
 */
196
0
  memcpy(xx, ttime, 2); /* year */
197
0
  year = atoi(xx);
198
0
  ttime += 2;
199
200
0
  if (year > 49)
201
0
    year += 1900;
202
0
  else
203
0
    year += 2000;
204
205
0
  return time2gtime(ttime, year);
206
0
}
207
208
/* returns a time_t value that contains the given time.
209
 * The given time is expressed as:
210
 * YEAR(4)|MONTH(2)|DAY(2)|HOUR(2)|MIN(2)|SEC(2)*
211
 */
212
time_t _gnutls_x509_generalTime2gtime(const char *ttime)
213
0
{
214
0
  char xx[5];
215
0
  int year;
216
217
0
  if (strlen(ttime) < 12) {
218
0
    gnutls_assert();
219
0
    return (time_t)-1;
220
0
  }
221
222
0
  if (strchr(ttime, 'Z') == 0) {
223
0
    gnutls_assert();
224
    /* required to be in GMT */
225
0
    return (time_t)-1;
226
0
  }
227
228
0
  if (strchr(ttime, '.') != 0) {
229
0
    gnutls_assert();
230
    /* no fractional seconds allowed */
231
0
    return (time_t)-1;
232
0
  }
233
0
  xx[4] = 0;
234
235
  /* get the year
236
 */
237
0
  memcpy(xx, ttime, 4); /* year */
238
0
  year = atoi(xx);
239
0
  ttime += 4;
240
241
0
  return time2gtime(ttime, year);
242
0
}
243
244
#pragma GCC diagnostic push
245
#pragma GCC diagnostic ignored "-Wformat-y2k"
246
/* tag will contain ASN1_TAG_UTCTime or ASN1_TAG_GENERALIZEDTime */
247
static int gtime_to_suitable_time(time_t gtime, char *str_time,
248
          size_t str_time_size, unsigned *tag)
249
0
{
250
0
  size_t ret;
251
0
  struct tm _tm;
252
253
0
  if (gtime == (time_t)-1
254
0
#if SIZEOF_LONG == 8
255
0
      || gtime >= 253402210800
256
0
#endif
257
0
  ) {
258
0
    if (tag)
259
0
      *tag = ASN1_TAG_GENERALIZEDTime;
260
0
    snprintf(str_time, str_time_size, "99991231235959Z");
261
0
    return 0;
262
0
  }
263
264
0
  if (!gmtime_r(&gtime, &_tm)) {
265
0
    gnutls_assert();
266
0
    return GNUTLS_E_INTERNAL_ERROR;
267
0
  }
268
269
0
  if (_tm.tm_year >= 150) {
270
0
    if (tag)
271
0
      *tag = ASN1_TAG_GENERALIZEDTime;
272
0
    ret = strftime(str_time, str_time_size, "%Y%m%d%H%M%SZ", &_tm);
273
0
  } else {
274
0
    if (tag)
275
0
      *tag = ASN1_TAG_UTCTime;
276
0
    ret = strftime(str_time, str_time_size, "%y%m%d%H%M%SZ", &_tm);
277
0
  }
278
279
0
  if (!ret) {
280
0
    gnutls_assert();
281
0
    return GNUTLS_E_SHORT_MEMORY_BUFFER;
282
0
  }
283
284
0
  return 0;
285
0
}
286
287
#pragma GCC diagnostic pop
288
289
static int gtime_to_generalTime(time_t gtime, char *str_time,
290
        size_t str_time_size)
291
0
{
292
0
  size_t ret;
293
0
  struct tm _tm;
294
295
0
  if (gtime == (time_t)-1
296
0
#if SIZEOF_LONG == 8
297
0
      || gtime >= 253402210800
298
0
#endif
299
0
  ) {
300
0
    snprintf(str_time, str_time_size, "99991231235959Z");
301
0
    return 0;
302
0
  }
303
304
0
  if (!gmtime_r(&gtime, &_tm)) {
305
0
    gnutls_assert();
306
0
    return GNUTLS_E_INTERNAL_ERROR;
307
0
  }
308
309
0
  ret = strftime(str_time, str_time_size, "%Y%m%d%H%M%SZ", &_tm);
310
0
  if (!ret) {
311
0
    gnutls_assert();
312
0
    return GNUTLS_E_SHORT_MEMORY_BUFFER;
313
0
  }
314
315
0
  return 0;
316
0
}
317
318
/* Extracts the time in time_t from the asn1_node given. When should
319
 * be something like "tbsCertList.thisUpdate".
320
 */
321
#define MAX_TIME 64
322
time_t _gnutls_x509_get_time(asn1_node c2, const char *where, int force_general)
323
0
{
324
0
  char ttime[MAX_TIME];
325
0
  char name[128];
326
0
  time_t c_time = (time_t)-1;
327
0
  int len, result;
328
329
0
  len = sizeof(ttime) - 1;
330
0
  result = asn1_read_value(c2, where, ttime, &len);
331
0
  if (result != ASN1_SUCCESS) {
332
0
    gnutls_assert();
333
0
    return (time_t)(-1);
334
0
  }
335
336
0
  if (force_general != 0) {
337
0
    c_time = _gnutls_x509_generalTime2gtime(ttime);
338
0
  } else {
339
0
    _gnutls_str_cpy(name, sizeof(name), where);
340
341
    /* choice */
342
0
    if (strcmp(ttime, "generalTime") == 0) {
343
0
      if (name[0] == 0)
344
0
        _gnutls_str_cpy(name, sizeof(name),
345
0
            "generalTime");
346
0
      else
347
0
        _gnutls_str_cat(name, sizeof(name),
348
0
            ".generalTime");
349
0
      len = sizeof(ttime) - 1;
350
0
      result = asn1_read_value(c2, name, ttime, &len);
351
0
      if (result == ASN1_SUCCESS)
352
0
        c_time = _gnutls_x509_generalTime2gtime(ttime);
353
0
    } else { /* UTCTIME */
354
0
      if (name[0] == 0)
355
0
        _gnutls_str_cpy(name, sizeof(name), "utcTime");
356
0
      else
357
0
        _gnutls_str_cat(name, sizeof(name), ".utcTime");
358
0
      len = sizeof(ttime) - 1;
359
0
      result = asn1_read_value(c2, name, ttime, &len);
360
0
      if (result == ASN1_SUCCESS)
361
0
        c_time = _gnutls_utcTime2gtime(ttime);
362
0
    }
363
364
    /* We cannot handle dates after 2031 in 32 bit machines.
365
     * a time_t of 64bits has to be used.
366
     */
367
0
    if (result != ASN1_SUCCESS) {
368
0
      gnutls_assert();
369
0
      return (time_t)(-1);
370
0
    }
371
0
  }
372
373
0
  return c_time;
374
0
}
375
376
/* Sets the time in time_t in the asn1_node given. Where should
377
 * be something like "tbsCertList.thisUpdate".
378
 */
379
int _gnutls_x509_set_time(asn1_node c2, const char *where, time_t tim,
380
        int force_general)
381
0
{
382
0
  char str_time[MAX_TIME];
383
0
  char name[128];
384
0
  int result, len;
385
0
  unsigned tag;
386
387
0
  if (force_general != 0) {
388
0
    result = gtime_to_generalTime(tim, str_time, sizeof(str_time));
389
0
    if (result < 0)
390
0
      return gnutls_assert_val(result);
391
0
    len = strlen(str_time);
392
0
    result = asn1_write_value(c2, where, str_time, len);
393
0
    if (result != ASN1_SUCCESS)
394
0
      return gnutls_assert_val(_gnutls_asn2err(result));
395
396
0
    return 0;
397
0
  }
398
399
0
  result = gtime_to_suitable_time(tim, str_time, sizeof(str_time), &tag);
400
0
  if (result < 0) {
401
0
    gnutls_assert();
402
0
    return result;
403
0
  }
404
405
0
  _gnutls_str_cpy(name, sizeof(name), where);
406
0
  if (tag == ASN1_TAG_UTCTime) {
407
0
    if ((result = asn1_write_value(c2, where, "utcTime", 1)) !=
408
0
        ASN1_SUCCESS) {
409
0
      gnutls_assert();
410
0
      return _gnutls_asn2err(result);
411
0
    }
412
0
    _gnutls_str_cat(name, sizeof(name), ".utcTime");
413
0
  } else {
414
0
    if ((result = asn1_write_value(c2, where, "generalTime", 1)) !=
415
0
        ASN1_SUCCESS) {
416
0
      gnutls_assert();
417
0
      return _gnutls_asn2err(result);
418
0
    }
419
0
    _gnutls_str_cat(name, sizeof(name), ".generalTime");
420
0
  }
421
422
0
  len = strlen(str_time);
423
0
  result = asn1_write_value(c2, name, str_time, len);
424
0
  if (result != ASN1_SUCCESS) {
425
0
    gnutls_assert();
426
0
    return _gnutls_asn2err(result);
427
0
  }
428
429
0
  return 0;
430
0
}
431
432
/* This will set a DER encoded Time element. To be used in fields
433
 * which are of the ANY.
434
 */
435
int _gnutls_x509_set_raw_time(asn1_node c2, const char *where, time_t tim)
436
0
{
437
0
  char str_time[MAX_TIME];
438
0
  uint8_t buf[128];
439
0
  int result, len, der_len;
440
0
  unsigned tag;
441
442
0
  result = gtime_to_suitable_time(tim, str_time, sizeof(str_time), &tag);
443
0
  if (result < 0)
444
0
    return gnutls_assert_val(result);
445
0
  len = strlen(str_time);
446
447
0
  buf[0] = tag;
448
0
  asn1_length_der(len, buf + 1, &der_len);
449
450
0
  if ((unsigned)len > sizeof(buf) - der_len - 1) {
451
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
452
0
  }
453
454
0
  memcpy(buf + 1 + der_len, str_time, len);
455
456
0
  result = asn1_write_value(c2, where, buf, len + 1 + der_len);
457
0
  if (result != ASN1_SUCCESS)
458
0
    return gnutls_assert_val(_gnutls_asn2err(result));
459
0
  return 0;
460
0
}