Coverage Report

Created: 2023-03-26 08:33

/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
248
gtime_to_suitable_time(time_t gtime, char *str_time, size_t str_time_size,
249
           unsigned *tag)
250
0
{
251
0
  size_t ret;
252
0
  struct tm _tm;
253
254
0
  if (gtime == (time_t) - 1
255
0
#if SIZEOF_LONG == 8
256
0
      || gtime >= 253402210800
257
0
#endif
258
0
      ) {
259
0
    if (tag)
260
0
      *tag = ASN1_TAG_GENERALIZEDTime;
261
0
    snprintf(str_time, str_time_size, "99991231235959Z");
262
0
    return 0;
263
0
  }
264
265
0
  if (!gmtime_r(&gtime, &_tm)) {
266
0
    gnutls_assert();
267
0
    return GNUTLS_E_INTERNAL_ERROR;
268
0
  }
269
270
0
  if (_tm.tm_year >= 150) {
271
0
    if (tag)
272
0
      *tag = ASN1_TAG_GENERALIZEDTime;
273
0
    ret = strftime(str_time, str_time_size, "%Y%m%d%H%M%SZ", &_tm);
274
0
  } else {
275
0
    if (tag)
276
0
      *tag = ASN1_TAG_UTCTime;
277
0
    ret = strftime(str_time, str_time_size, "%y%m%d%H%M%SZ", &_tm);
278
0
  }
279
280
0
  if (!ret) {
281
0
    gnutls_assert();
282
0
    return GNUTLS_E_SHORT_MEMORY_BUFFER;
283
0
  }
284
285
0
  return 0;
286
0
}
287
288
#pragma GCC diagnostic pop
289
290
static int
291
gtime_to_generalTime(time_t gtime, char *str_time, size_t str_time_size)
292
0
{
293
0
  size_t ret;
294
0
  struct tm _tm;
295
296
0
  if (gtime == (time_t) - 1
297
0
#if SIZEOF_LONG == 8
298
0
      || gtime >= 253402210800
299
0
#endif
300
0
      ) {
301
0
    snprintf(str_time, str_time_size, "99991231235959Z");
302
0
    return 0;
303
0
  }
304
305
0
  if (!gmtime_r(&gtime, &_tm)) {
306
0
    gnutls_assert();
307
0
    return GNUTLS_E_INTERNAL_ERROR;
308
0
  }
309
310
0
  ret = strftime(str_time, str_time_size, "%Y%m%d%H%M%SZ", &_tm);
311
0
  if (!ret) {
312
0
    gnutls_assert();
313
0
    return GNUTLS_E_SHORT_MEMORY_BUFFER;
314
0
  }
315
316
0
  return 0;
317
0
}
318
319
/* Extracts the time in time_t from the asn1_node given. When should
320
 * be something like "tbsCertList.thisUpdate".
321
 */
322
#define MAX_TIME 64
323
time_t _gnutls_x509_get_time(asn1_node c2, const char *where, int force_general)
324
0
{
325
0
  char ttime[MAX_TIME];
326
0
  char name[128];
327
0
  time_t c_time = (time_t) - 1;
328
0
  int len, result;
329
330
0
  len = sizeof(ttime) - 1;
331
0
  result = asn1_read_value(c2, where, ttime, &len);
332
0
  if (result != ASN1_SUCCESS) {
333
0
    gnutls_assert();
334
0
    return (time_t) (-1);
335
0
  }
336
337
0
  if (force_general != 0) {
338
0
    c_time = _gnutls_x509_generalTime2gtime(ttime);
339
0
  } else {
340
0
    _gnutls_str_cpy(name, sizeof(name), where);
341
342
    /* choice */
343
0
    if (strcmp(ttime, "generalTime") == 0) {
344
0
      if (name[0] == 0)
345
0
        _gnutls_str_cpy(name, sizeof(name),
346
0
            "generalTime");
347
0
      else
348
0
        _gnutls_str_cat(name, sizeof(name),
349
0
            ".generalTime");
350
0
      len = sizeof(ttime) - 1;
351
0
      result = asn1_read_value(c2, name, ttime, &len);
352
0
      if (result == ASN1_SUCCESS)
353
0
        c_time = _gnutls_x509_generalTime2gtime(ttime);
354
0
    } else { /* UTCTIME */
355
0
      if (name[0] == 0)
356
0
        _gnutls_str_cpy(name, sizeof(name), "utcTime");
357
0
      else
358
0
        _gnutls_str_cat(name, sizeof(name), ".utcTime");
359
0
      len = sizeof(ttime) - 1;
360
0
      result = asn1_read_value(c2, name, ttime, &len);
361
0
      if (result == ASN1_SUCCESS)
362
0
        c_time = _gnutls_utcTime2gtime(ttime);
363
0
    }
364
365
    /* We cannot handle dates after 2031 in 32 bit machines.
366
     * a time_t of 64bits has to be used.
367
     */
368
0
    if (result != ASN1_SUCCESS) {
369
0
      gnutls_assert();
370
0
      return (time_t) (-1);
371
0
    }
372
0
  }
373
374
0
  return c_time;
375
0
}
376
377
/* Sets the time in time_t in the asn1_node given. Where should
378
 * be something like "tbsCertList.thisUpdate".
379
 */
380
int
381
_gnutls_x509_set_time(asn1_node c2, const char *where, time_t tim,
382
          int force_general)
383
0
{
384
0
  char str_time[MAX_TIME];
385
0
  char name[128];
386
0
  int result, len;
387
0
  unsigned tag;
388
389
0
  if (force_general != 0) {
390
0
    result = gtime_to_generalTime(tim, str_time, sizeof(str_time));
391
0
    if (result < 0)
392
0
      return gnutls_assert_val(result);
393
0
    len = strlen(str_time);
394
0
    result = asn1_write_value(c2, where, str_time, len);
395
0
    if (result != ASN1_SUCCESS)
396
0
      return gnutls_assert_val(_gnutls_asn2err(result));
397
398
0
    return 0;
399
0
  }
400
401
0
  result = gtime_to_suitable_time(tim, str_time, sizeof(str_time), &tag);
402
0
  if (result < 0) {
403
0
    gnutls_assert();
404
0
    return result;
405
0
  }
406
407
0
  _gnutls_str_cpy(name, sizeof(name), where);
408
0
  if (tag == ASN1_TAG_UTCTime) {
409
0
    if ((result = asn1_write_value(c2, where, "utcTime", 1)) < 0) {
410
0
      gnutls_assert();
411
0
      return _gnutls_asn2err(result);
412
0
    }
413
0
    _gnutls_str_cat(name, sizeof(name), ".utcTime");
414
0
  } else {
415
0
    if ((result =
416
0
         asn1_write_value(c2, where, "generalTime", 1)) < 0) {
417
0
      gnutls_assert();
418
0
      return _gnutls_asn2err(result);
419
0
    }
420
0
    _gnutls_str_cat(name, sizeof(name), ".generalTime");
421
0
  }
422
423
0
  len = strlen(str_time);
424
0
  result = asn1_write_value(c2, name, str_time, len);
425
0
  if (result != ASN1_SUCCESS) {
426
0
    gnutls_assert();
427
0
    return _gnutls_asn2err(result);
428
0
  }
429
430
0
  return 0;
431
0
}
432
433
/* This will set a DER encoded Time element. To be used in fields
434
 * which are of the ANY.
435
 */
436
int _gnutls_x509_set_raw_time(asn1_node c2, const char *where, time_t tim)
437
0
{
438
0
  char str_time[MAX_TIME];
439
0
  uint8_t buf[128];
440
0
  int result, len, der_len;
441
0
  unsigned tag;
442
443
0
  result = gtime_to_suitable_time(tim, str_time, sizeof(str_time), &tag);
444
0
  if (result < 0)
445
0
    return gnutls_assert_val(result);
446
0
  len = strlen(str_time);
447
448
0
  buf[0] = tag;
449
0
  asn1_length_der(len, buf + 1, &der_len);
450
451
0
  if ((unsigned)len > sizeof(buf) - der_len - 1) {
452
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
453
0
  }
454
455
0
  memcpy(buf + 1 + der_len, str_time, len);
456
457
0
  result = asn1_write_value(c2, where, buf, len + 1 + der_len);
458
0
  if (result != ASN1_SUCCESS)
459
0
    return gnutls_assert_val(_gnutls_asn2err(result));
460
0
  return 0;
461
0
}