Blame lib/x509/time.c

Packit aea12f
/*
Packit aea12f
 * Copyright (C) 2003-2016 Free Software Foundation, Inc.
Packit aea12f
 * Copyright (C) 2016 Red Hat, Inc.
Packit aea12f
 *
Packit aea12f
 * Author: Nikos Mavrogiannopoulos
Packit aea12f
 *
Packit aea12f
 * This file is part of GnuTLS.
Packit aea12f
 *
Packit aea12f
 * The GnuTLS is free software; you can redistribute it and/or
Packit aea12f
 * modify it under the terms of the GNU Lesser General Public License
Packit aea12f
 * as published by the Free Software Foundation; either version 2.1 of
Packit aea12f
 * the License, or (at your option) any later version.
Packit aea12f
 *
Packit aea12f
 * This library is distributed in the hope that it will be useful, but
Packit aea12f
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit aea12f
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit aea12f
 * Lesser General Public License for more details.
Packit aea12f
 *
Packit aea12f
 * You should have received a copy of the GNU Lesser General Public License
Packit aea12f
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
Packit aea12f
 *
Packit aea12f
 */
Packit aea12f
Packit aea12f
#include "gnutls_int.h"
Packit aea12f
#include <libtasn1.h>
Packit aea12f
#include <datum.h>
Packit aea12f
#include <global.h>
Packit aea12f
#include "errors.h"
Packit aea12f
#include <str.h>
Packit aea12f
#include <x509.h>
Packit aea12f
#include <num.h>
Packit aea12f
#include <x509_b64.h>
Packit aea12f
#include "x509_int.h"
Packit aea12f
#include "extras/hex.h"
Packit aea12f
#include <common.h>
Packit aea12f
Packit aea12f
time_t _gnutls_utcTime2gtime(const char *ttime);
Packit aea12f
Packit aea12f
/* TIME functions 
Packit aea12f
 * Conversions between generalized or UTC time to time_t
Packit aea12f
 *
Packit aea12f
 */
Packit aea12f
Packit aea12f
/* This is an emulation of the struct tm.
Packit aea12f
 * Since we do not use libc's functions, we don't need to
Packit aea12f
 * depend on the libc structure.
Packit aea12f
 */
Packit aea12f
typedef struct fake_tm {
Packit aea12f
	int tm_mon;
Packit aea12f
	int tm_year;		/* FULL year - ie 1971 */
Packit aea12f
	int tm_mday;
Packit aea12f
	int tm_hour;
Packit aea12f
	int tm_min;
Packit aea12f
	int tm_sec;
Packit aea12f
} fake_tm;
Packit aea12f
Packit aea12f
/* The mktime_utc function is due to Russ Allbery (rra@stanford.edu),
Packit aea12f
 * who placed it under public domain:
Packit aea12f
 */
Packit aea12f
Packit aea12f
/* The number of days in each month. 
Packit aea12f
 */
Packit aea12f
static const int MONTHDAYS[] = {
Packit aea12f
	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
Packit aea12f
};
Packit aea12f
Packit aea12f
    /* Whether a given year is a leap year. */
Packit aea12f
#define ISLEAP(year) \
Packit aea12f
	(((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0))
Packit aea12f
Packit aea12f
/*
Packit aea12f
 **  Given a struct tm representing a calendar time in UTC, convert it to
Packit aea12f
 **  seconds since epoch.  Returns (time_t) -1 if the time is not
Packit aea12f
 **  convertible.  Note that this function does not canonicalize the provided
Packit aea12f
 **  struct tm, nor does it allow out of range values or years before 1970.
Packit aea12f
 */
Packit aea12f
static time_t mktime_utc(const struct fake_tm *tm)
Packit aea12f
{
Packit aea12f
	time_t result = 0;
Packit aea12f
	int i;
Packit aea12f
Packit aea12f
/* We do allow some ill-formed dates, but we don't do anything special
Packit aea12f
 * with them and our callers really shouldn't pass them to us.  Do
Packit aea12f
 * explicitly disallow the ones that would cause invalid array accesses
Packit aea12f
 * or other algorithm problems. 
Packit aea12f
 */
Packit aea12f
	if (tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 1970)
Packit aea12f
		return (time_t) - 1;
Packit aea12f
Packit aea12f
	/* Check for "obvious" mistakes in dates */
Packit aea12f
	if (tm->tm_sec > 60 || tm->tm_min > 59 || tm->tm_mday > 31 || tm->tm_mday < 1 || tm->tm_hour > 23)
Packit aea12f
		return (time_t) - 1;
Packit aea12f
Packit aea12f
/* Convert to a time_t. 
Packit aea12f
 */
Packit aea12f
	for (i = 1970; i < tm->tm_year; i++)
Packit aea12f
		result += 365 + ISLEAP(i);
Packit aea12f
	for (i = 0; i < tm->tm_mon; i++)
Packit aea12f
		result += MONTHDAYS[i];
Packit aea12f
	if (tm->tm_mon > 1 && ISLEAP(tm->tm_year))
Packit aea12f
		result++;
Packit aea12f
	result = 24 * (result + tm->tm_mday - 1) + tm->tm_hour;
Packit aea12f
	result = 60 * result + tm->tm_min;
Packit aea12f
	result = 60 * result + tm->tm_sec;
Packit aea12f
	return result;
Packit aea12f
}
Packit aea12f
Packit aea12f
Packit aea12f
/* this one will parse dates of the form:
Packit aea12f
 * month|day|hour|minute|sec* (2 chars each)
Packit aea12f
 * and year is given. Returns a time_t date.
Packit aea12f
 */
Packit aea12f
static time_t time2gtime(const char *ttime, int year)
Packit aea12f
{
Packit aea12f
	char xx[4];
Packit aea12f
	struct fake_tm etime;
Packit aea12f
Packit aea12f
	if (strlen(ttime) < 8) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		return (time_t) - 1;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	etime.tm_year = year;
Packit aea12f
Packit aea12f
	/* In order to work with 32 bit
Packit aea12f
	 * time_t.
Packit aea12f
	 */
Packit aea12f
	if (sizeof(time_t) <= 4 && etime.tm_year >= 2038)
Packit aea12f
		return (time_t) 2145914603;	/* 2037-12-31 23:23:23 */
Packit aea12f
Packit aea12f
	if (etime.tm_year < 1970)
Packit aea12f
		return (time_t) 0;
Packit aea12f
Packit aea12f
	xx[2] = 0;
Packit aea12f
Packit aea12f
/* get the month
Packit aea12f
 */
Packit aea12f
	memcpy(xx, ttime, 2);	/* month */
Packit aea12f
	etime.tm_mon = atoi(xx) - 1;
Packit aea12f
	ttime += 2;
Packit aea12f
Packit aea12f
/* get the day
Packit aea12f
 */
Packit aea12f
	memcpy(xx, ttime, 2);	/* day */
Packit aea12f
	etime.tm_mday = atoi(xx);
Packit aea12f
	ttime += 2;
Packit aea12f
Packit aea12f
/* get the hour
Packit aea12f
 */
Packit aea12f
	memcpy(xx, ttime, 2);	/* hour */
Packit aea12f
	etime.tm_hour = atoi(xx);
Packit aea12f
	ttime += 2;
Packit aea12f
Packit aea12f
/* get the minutes
Packit aea12f
 */
Packit aea12f
	memcpy(xx, ttime, 2);	/* minutes */
Packit aea12f
	etime.tm_min = atoi(xx);
Packit aea12f
	ttime += 2;
Packit aea12f
Packit aea12f
	if (strlen(ttime) >= 2) {
Packit aea12f
		memcpy(xx, ttime, 2);
Packit aea12f
		etime.tm_sec = atoi(xx);
Packit aea12f
	} else
Packit aea12f
		etime.tm_sec = 0;
Packit aea12f
Packit aea12f
	return mktime_utc(&etime);
Packit aea12f
}
Packit aea12f
Packit aea12f
Packit aea12f
/* returns a time_t value that contains the given time.
Packit aea12f
 * The given time is expressed as:
Packit aea12f
 * YEAR(2)|MONTH(2)|DAY(2)|HOUR(2)|MIN(2)|SEC(2)*
Packit aea12f
 *
Packit aea12f
 * (seconds are optional)
Packit aea12f
 */
Packit aea12f
time_t _gnutls_utcTime2gtime(const char *ttime)
Packit aea12f
{
Packit aea12f
	char xx[3];
Packit aea12f
	int year;
Packit aea12f
Packit aea12f
	if (strlen(ttime) < 10) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		return (time_t) - 1;
Packit aea12f
	}
Packit aea12f
	xx[2] = 0;
Packit aea12f
/* get the year
Packit aea12f
 */
Packit aea12f
	memcpy(xx, ttime, 2);	/* year */
Packit aea12f
	year = atoi(xx);
Packit aea12f
	ttime += 2;
Packit aea12f
Packit aea12f
	if (year > 49)
Packit aea12f
		year += 1900;
Packit aea12f
	else
Packit aea12f
		year += 2000;
Packit aea12f
Packit aea12f
	return time2gtime(ttime, year);
Packit aea12f
}
Packit aea12f
Packit aea12f
/* returns a time_t value that contains the given time.
Packit aea12f
 * The given time is expressed as:
Packit aea12f
 * YEAR(4)|MONTH(2)|DAY(2)|HOUR(2)|MIN(2)|SEC(2)*
Packit aea12f
 */
Packit aea12f
time_t _gnutls_x509_generalTime2gtime(const char *ttime)
Packit aea12f
{
Packit aea12f
	char xx[5];
Packit aea12f
	int year;
Packit aea12f
Packit aea12f
	if (strlen(ttime) < 12) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		return (time_t) - 1;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	if (strchr(ttime, 'Z') == 0) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		/* required to be in GMT */
Packit aea12f
		return (time_t) - 1;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	if (strchr(ttime, '.') != 0) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		/* no fractional seconds allowed */
Packit aea12f
		return (time_t) - 1;
Packit aea12f
	}
Packit aea12f
	xx[4] = 0;
Packit aea12f
Packit aea12f
/* get the year
Packit aea12f
 */
Packit aea12f
	memcpy(xx, ttime, 4);	/* year */
Packit aea12f
	year = atoi(xx);
Packit aea12f
	ttime += 4;
Packit aea12f
Packit aea12f
	return time2gtime(ttime, year);
Packit aea12f
}
Packit aea12f
Packit aea12f
/* tag will contain ASN1_TAG_UTCTime or ASN1_TAG_GENERALIZEDTime */
Packit aea12f
static int
Packit aea12f
gtime_to_suitable_time(time_t gtime, char *str_time, size_t str_time_size, unsigned *tag)
Packit aea12f
{
Packit aea12f
	size_t ret;
Packit aea12f
	struct tm _tm;
Packit aea12f
Packit aea12f
	if (gtime == (time_t)-1
Packit aea12f
#if SIZEOF_LONG == 8
Packit aea12f
		|| gtime >= 253402210800
Packit aea12f
#endif
Packit aea12f
	 ) {
Packit aea12f
		if (tag)
Packit aea12f
			*tag = ASN1_TAG_GENERALIZEDTime;
Packit aea12f
		snprintf(str_time, str_time_size, "99991231235959Z");
Packit aea12f
		return 0;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	if (!gmtime_r(&gtime, &_tm)) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		return GNUTLS_E_INTERNAL_ERROR;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	if (_tm.tm_year >= 150) {
Packit aea12f
		if (tag)
Packit aea12f
			*tag = ASN1_TAG_GENERALIZEDTime;
Packit aea12f
		ret = strftime(str_time, str_time_size, "%Y%m%d%H%M%SZ", &_tm);
Packit aea12f
	} else {
Packit aea12f
		if (tag)
Packit aea12f
			*tag = ASN1_TAG_UTCTime;
Packit aea12f
		ret = strftime(str_time, str_time_size, "%y%m%d%H%M%SZ", &_tm);
Packit aea12f
	}
Packit aea12f
	if (!ret) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		return GNUTLS_E_SHORT_MEMORY_BUFFER;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return 0;
Packit aea12f
}
Packit aea12f
Packit aea12f
static int
Packit aea12f
gtime_to_generalTime(time_t gtime, char *str_time, size_t str_time_size)
Packit aea12f
{
Packit aea12f
	size_t ret;
Packit aea12f
	struct tm _tm;
Packit aea12f
	
Packit aea12f
	if (gtime == (time_t)-1
Packit aea12f
#if SIZEOF_LONG == 8
Packit aea12f
		|| gtime >= 253402210800
Packit aea12f
#endif
Packit aea12f
	 ) {
Packit aea12f
		snprintf(str_time, str_time_size, "99991231235959Z");
Packit aea12f
		return 0;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	if (!gmtime_r(&gtime, &_tm)) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		return GNUTLS_E_INTERNAL_ERROR;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	ret = strftime(str_time, str_time_size, "%Y%m%d%H%M%SZ", &_tm);
Packit aea12f
	if (!ret) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		return GNUTLS_E_SHORT_MEMORY_BUFFER;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return 0;
Packit aea12f
}
Packit aea12f
Packit aea12f
Packit aea12f
/* Extracts the time in time_t from the ASN1_TYPE given. When should
Packit aea12f
 * be something like "tbsCertList.thisUpdate".
Packit aea12f
 */
Packit aea12f
#define MAX_TIME 64
Packit aea12f
time_t _gnutls_x509_get_time(ASN1_TYPE c2, const char *where, int force_general)
Packit aea12f
{
Packit aea12f
	char ttime[MAX_TIME];
Packit aea12f
	char name[128];
Packit aea12f
	time_t c_time = (time_t) - 1;
Packit aea12f
	int len, result;
Packit aea12f
Packit aea12f
	len = sizeof(ttime) - 1;
Packit aea12f
	result = asn1_read_value(c2, where, ttime, &len;;
Packit aea12f
	if (result != ASN1_SUCCESS) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		return (time_t) (-1);
Packit aea12f
	}
Packit aea12f
Packit aea12f
	if (force_general != 0) {
Packit aea12f
		c_time = _gnutls_x509_generalTime2gtime(ttime);
Packit aea12f
	} else {
Packit aea12f
		_gnutls_str_cpy(name, sizeof(name), where);
Packit aea12f
Packit aea12f
		/* choice */
Packit aea12f
		if (strcmp(ttime, "generalTime") == 0) {
Packit aea12f
			if (name[0] == 0)
Packit aea12f
				_gnutls_str_cpy(name, sizeof(name),
Packit aea12f
						"generalTime");
Packit aea12f
			else
Packit aea12f
				_gnutls_str_cat(name, sizeof(name),
Packit aea12f
						".generalTime");
Packit aea12f
			len = sizeof(ttime) - 1;
Packit aea12f
			result = asn1_read_value(c2, name, ttime, &len;;
Packit aea12f
			if (result == ASN1_SUCCESS)
Packit aea12f
				c_time =
Packit aea12f
				    _gnutls_x509_generalTime2gtime(ttime);
Packit aea12f
		} else {	/* UTCTIME */
Packit aea12f
			if (name[0] == 0)
Packit aea12f
				_gnutls_str_cpy(name, sizeof(name), "utcTime");
Packit aea12f
			else
Packit aea12f
				_gnutls_str_cat(name, sizeof(name), ".utcTime");
Packit aea12f
			len = sizeof(ttime) - 1;
Packit aea12f
			result = asn1_read_value(c2, name, ttime, &len;;
Packit aea12f
			if (result == ASN1_SUCCESS)
Packit aea12f
				c_time = _gnutls_utcTime2gtime(ttime);
Packit aea12f
		}
Packit aea12f
Packit aea12f
		/* We cannot handle dates after 2031 in 32 bit machines.
Packit aea12f
		 * a time_t of 64bits has to be used.
Packit aea12f
		 */
Packit aea12f
		if (result != ASN1_SUCCESS) {
Packit aea12f
			gnutls_assert();
Packit aea12f
			return (time_t) (-1);
Packit aea12f
		}
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return c_time;
Packit aea12f
}
Packit aea12f
Packit aea12f
/* Sets the time in time_t in the ASN1_TYPE given. Where should
Packit aea12f
 * be something like "tbsCertList.thisUpdate".
Packit aea12f
 */
Packit aea12f
int
Packit aea12f
_gnutls_x509_set_time(ASN1_TYPE c2, const char *where, time_t tim,
Packit aea12f
		      int force_general)
Packit aea12f
{
Packit aea12f
	char str_time[MAX_TIME];
Packit aea12f
	char name[128];
Packit aea12f
	int result, len;
Packit aea12f
	unsigned tag;
Packit aea12f
Packit aea12f
	if (force_general != 0) {
Packit aea12f
		result =
Packit aea12f
		    gtime_to_generalTime(tim, str_time, sizeof(str_time));
Packit aea12f
		if (result < 0)
Packit aea12f
			return gnutls_assert_val(result);
Packit aea12f
		len = strlen(str_time);
Packit aea12f
		result = asn1_write_value(c2, where, str_time, len);
Packit aea12f
		if (result != ASN1_SUCCESS)
Packit aea12f
			return gnutls_assert_val(_gnutls_asn2err(result));
Packit aea12f
Packit aea12f
		return 0;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	result = gtime_to_suitable_time(tim, str_time, sizeof(str_time), &tag;;
Packit aea12f
	if (result < 0) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		return result;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	_gnutls_str_cpy(name, sizeof(name), where);
Packit aea12f
	if (tag == ASN1_TAG_UTCTime) {
Packit aea12f
		if ((result = asn1_write_value(c2, where, "utcTime", 1)) < 0) {
Packit aea12f
			gnutls_assert();
Packit aea12f
			return _gnutls_asn2err(result);
Packit aea12f
		}
Packit aea12f
		_gnutls_str_cat(name, sizeof(name), ".utcTime");
Packit aea12f
	} else {
Packit aea12f
		if ((result = asn1_write_value(c2, where, "generalTime", 1)) < 0) {
Packit aea12f
			gnutls_assert();
Packit aea12f
			return _gnutls_asn2err(result);
Packit aea12f
		}
Packit aea12f
		_gnutls_str_cat(name, sizeof(name), ".generalTime");
Packit aea12f
	}
Packit aea12f
Packit aea12f
	len = strlen(str_time);
Packit aea12f
	result = asn1_write_value(c2, name, str_time, len);
Packit aea12f
	if (result != ASN1_SUCCESS) {
Packit aea12f
		gnutls_assert();
Packit aea12f
		return _gnutls_asn2err(result);
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return 0;
Packit aea12f
}
Packit aea12f
Packit aea12f
/* This will set a DER encoded Time element. To be used in fields
Packit aea12f
 * which are of the ANY.
Packit aea12f
 */
Packit aea12f
int
Packit aea12f
_gnutls_x509_set_raw_time(ASN1_TYPE c2, const char *where, time_t tim)
Packit aea12f
{
Packit aea12f
	char str_time[MAX_TIME];
Packit aea12f
	uint8_t buf[128];
Packit aea12f
	int result, len, der_len;
Packit aea12f
	unsigned tag;
Packit aea12f
Packit aea12f
	result =
Packit aea12f
	    gtime_to_suitable_time(tim, str_time, sizeof(str_time), &tag;;
Packit aea12f
	if (result < 0)
Packit aea12f
		return gnutls_assert_val(result);
Packit aea12f
	len = strlen(str_time);
Packit aea12f
Packit aea12f
	buf[0] = tag;
Packit aea12f
	asn1_length_der(len, buf+1, &der_len);
Packit aea12f
Packit aea12f
	if ((unsigned)len > sizeof(buf)-der_len-1) {
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
Packit aea12f
	}
Packit aea12f
Packit aea12f
	memcpy(buf+1+der_len, str_time, len);
Packit aea12f
Packit aea12f
	result = asn1_write_value(c2, where, buf, len+1+der_len);
Packit aea12f
	if (result != ASN1_SUCCESS)
Packit aea12f
		return gnutls_assert_val(_gnutls_asn2err(result));
Packit aea12f
	return 0;
Packit aea12f
}
Packit aea12f