1*59c8e88eSDag-Erling Smørgrav/* $OpenBSD: a_time_tm.c,v 1.15 2018/04/25 11:48:21 tb Exp $ */ 2*59c8e88eSDag-Erling Smørgrav/* 3*59c8e88eSDag-Erling Smørgrav * Copyright (c) 2015 Bob Beck <beck@openbsd.org> 4*59c8e88eSDag-Erling Smørgrav * 5*59c8e88eSDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any 6*59c8e88eSDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above 7*59c8e88eSDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies. 8*59c8e88eSDag-Erling Smørgrav * 9*59c8e88eSDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10*59c8e88eSDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11*59c8e88eSDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12*59c8e88eSDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13*59c8e88eSDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14*59c8e88eSDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15*59c8e88eSDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16*59c8e88eSDag-Erling Smørgrav */ 17*59c8e88eSDag-Erling Smørgrav 18*59c8e88eSDag-Erling Smørgrav#include "includes.h" 19*59c8e88eSDag-Erling Smørgrav 20*59c8e88eSDag-Erling Smørgrav#include <ctype.h> 21*59c8e88eSDag-Erling Smørgrav#include <limits.h> 22*59c8e88eSDag-Erling Smørgrav#include <stdio.h> 23*59c8e88eSDag-Erling Smørgrav#include <string.h> 24*59c8e88eSDag-Erling Smørgrav#include <time.h> 25*59c8e88eSDag-Erling Smørgrav 26*59c8e88eSDag-Erling Smørgrav#define GENTIME_LENGTH 15 27*59c8e88eSDag-Erling Smørgrav#define UTCTIME_LENGTH 13 28*59c8e88eSDag-Erling Smørgrav 29*59c8e88eSDag-Erling Smørgrav#define V_ASN1_UTCTIME 23 30*59c8e88eSDag-Erling Smørgrav#define V_ASN1_GENERALIZEDTIME 24 31*59c8e88eSDag-Erling Smørgrav 32*59c8e88eSDag-Erling Smørgravint 33*59c8e88eSDag-Erling SmørgravASN1_time_tm_cmp(struct tm *tm1, struct tm *tm2) 34*59c8e88eSDag-Erling Smørgrav{ 35*59c8e88eSDag-Erling Smørgrav if (tm1->tm_year < tm2->tm_year) 36*59c8e88eSDag-Erling Smørgrav return (-1); 37*59c8e88eSDag-Erling Smørgrav if (tm1->tm_year > tm2->tm_year) 38*59c8e88eSDag-Erling Smørgrav return (1); 39*59c8e88eSDag-Erling Smørgrav if (tm1->tm_mon < tm2->tm_mon) 40*59c8e88eSDag-Erling Smørgrav return (-1); 41*59c8e88eSDag-Erling Smørgrav if (tm1->tm_mon > tm2->tm_mon) 42*59c8e88eSDag-Erling Smørgrav return (1); 43*59c8e88eSDag-Erling Smørgrav if (tm1->tm_mday < tm2->tm_mday) 44*59c8e88eSDag-Erling Smørgrav return (-1); 45*59c8e88eSDag-Erling Smørgrav if (tm1->tm_mday > tm2->tm_mday) 46*59c8e88eSDag-Erling Smørgrav return (1); 47*59c8e88eSDag-Erling Smørgrav if (tm1->tm_hour < tm2->tm_hour) 48*59c8e88eSDag-Erling Smørgrav return (-1); 49*59c8e88eSDag-Erling Smørgrav if (tm1->tm_hour > tm2->tm_hour) 50*59c8e88eSDag-Erling Smørgrav return (1); 51*59c8e88eSDag-Erling Smørgrav if (tm1->tm_min < tm2->tm_min) 52*59c8e88eSDag-Erling Smørgrav return (-1); 53*59c8e88eSDag-Erling Smørgrav if (tm1->tm_min > tm2->tm_min) 54*59c8e88eSDag-Erling Smørgrav return (1); 55*59c8e88eSDag-Erling Smørgrav if (tm1->tm_sec < tm2->tm_sec) 56*59c8e88eSDag-Erling Smørgrav return (-1); 57*59c8e88eSDag-Erling Smørgrav if (tm1->tm_sec > tm2->tm_sec) 58*59c8e88eSDag-Erling Smørgrav return (1); 59*59c8e88eSDag-Erling Smørgrav return 0; 60*59c8e88eSDag-Erling Smørgrav} 61*59c8e88eSDag-Erling Smørgrav 62*59c8e88eSDag-Erling Smørgravint 63*59c8e88eSDag-Erling SmørgravASN1_time_tm_clamp_notafter(struct tm *tm) 64*59c8e88eSDag-Erling Smørgrav{ 65*59c8e88eSDag-Erling Smørgrav#ifdef SMALL_TIME_T 66*59c8e88eSDag-Erling Smørgrav struct tm broken_os_epoch_tm; 67*59c8e88eSDag-Erling Smørgrav time_t broken_os_epoch_time = INT_MAX; 68*59c8e88eSDag-Erling Smørgrav 69*59c8e88eSDag-Erling Smørgrav if (gmtime_r(&broken_os_epoch_time, &broken_os_epoch_tm) == NULL) 70*59c8e88eSDag-Erling Smørgrav return 0; 71*59c8e88eSDag-Erling Smørgrav 72*59c8e88eSDag-Erling Smørgrav if (ASN1_time_tm_cmp(tm, &broken_os_epoch_tm) == 1) 73*59c8e88eSDag-Erling Smørgrav memcpy(tm, &broken_os_epoch_tm, sizeof(*tm)); 74*59c8e88eSDag-Erling Smørgrav#endif 75*59c8e88eSDag-Erling Smørgrav return 1; 76*59c8e88eSDag-Erling Smørgrav} 77*59c8e88eSDag-Erling Smørgrav 78*59c8e88eSDag-Erling Smørgrav/* 79*59c8e88eSDag-Erling Smørgrav * Parse an RFC 5280 format ASN.1 time string. 80*59c8e88eSDag-Erling Smørgrav * 81*59c8e88eSDag-Erling Smørgrav * mode must be: 82*59c8e88eSDag-Erling Smørgrav * 0 if we expect to parse a time as specified in RFC 5280 for an X509 object. 83*59c8e88eSDag-Erling Smørgrav * V_ASN1_UTCTIME if we wish to parse an RFC5280 format UTC time. 84*59c8e88eSDag-Erling Smørgrav * V_ASN1_GENERALIZEDTIME if we wish to parse an RFC5280 format Generalized time. 85*59c8e88eSDag-Erling Smørgrav * 86*59c8e88eSDag-Erling Smørgrav * Returns: 87*59c8e88eSDag-Erling Smørgrav * -1 if the string was invalid. 88*59c8e88eSDag-Erling Smørgrav * V_ASN1_UTCTIME if the string validated as a UTC time string. 89*59c8e88eSDag-Erling Smørgrav * V_ASN1_GENERALIZEDTIME if the string validated as a Generalized time string. 90*59c8e88eSDag-Erling Smørgrav * 91*59c8e88eSDag-Erling Smørgrav * Fills in *tm with the corresponding time if tm is non NULL. 92*59c8e88eSDag-Erling Smørgrav */ 93*59c8e88eSDag-Erling Smørgrav#define ATOI2(ar) ((ar) += 2, ((ar)[-2] - '0') * 10 + ((ar)[-1] - '0')) 94*59c8e88eSDag-Erling Smørgravint 95*59c8e88eSDag-Erling SmørgravASN1_time_parse(const char *bytes, size_t len, struct tm *tm, int mode) 96*59c8e88eSDag-Erling Smørgrav{ 97*59c8e88eSDag-Erling Smørgrav size_t i; 98*59c8e88eSDag-Erling Smørgrav int type = 0; 99*59c8e88eSDag-Erling Smørgrav struct tm ltm; 100*59c8e88eSDag-Erling Smørgrav struct tm *lt; 101*59c8e88eSDag-Erling Smørgrav const char *p; 102*59c8e88eSDag-Erling Smørgrav 103*59c8e88eSDag-Erling Smørgrav if (bytes == NULL) 104*59c8e88eSDag-Erling Smørgrav return (-1); 105*59c8e88eSDag-Erling Smørgrav 106*59c8e88eSDag-Erling Smørgrav /* Constrain to valid lengths. */ 107*59c8e88eSDag-Erling Smørgrav if (len != UTCTIME_LENGTH && len != GENTIME_LENGTH) 108*59c8e88eSDag-Erling Smørgrav return (-1); 109*59c8e88eSDag-Erling Smørgrav 110*59c8e88eSDag-Erling Smørgrav lt = tm; 111*59c8e88eSDag-Erling Smørgrav if (lt == NULL) { 112*59c8e88eSDag-Erling Smørgrav memset(<m, 0, sizeof(ltm)); 113*59c8e88eSDag-Erling Smørgrav lt = <m; 114*59c8e88eSDag-Erling Smørgrav } 115*59c8e88eSDag-Erling Smørgrav 116*59c8e88eSDag-Erling Smørgrav /* Timezone is required and must be GMT (Zulu). */ 117*59c8e88eSDag-Erling Smørgrav if (bytes[len - 1] != 'Z') 118*59c8e88eSDag-Erling Smørgrav return (-1); 119*59c8e88eSDag-Erling Smørgrav 120*59c8e88eSDag-Erling Smørgrav /* Make sure everything else is digits. */ 121*59c8e88eSDag-Erling Smørgrav for (i = 0; i < len - 1; i++) { 122*59c8e88eSDag-Erling Smørgrav if (isdigit((unsigned char)bytes[i])) 123*59c8e88eSDag-Erling Smørgrav continue; 124*59c8e88eSDag-Erling Smørgrav return (-1); 125*59c8e88eSDag-Erling Smørgrav } 126*59c8e88eSDag-Erling Smørgrav 127*59c8e88eSDag-Erling Smørgrav /* 128*59c8e88eSDag-Erling Smørgrav * Validate and convert the time 129*59c8e88eSDag-Erling Smørgrav */ 130*59c8e88eSDag-Erling Smørgrav p = bytes; 131*59c8e88eSDag-Erling Smørgrav switch (len) { 132*59c8e88eSDag-Erling Smørgrav case GENTIME_LENGTH: 133*59c8e88eSDag-Erling Smørgrav if (mode == V_ASN1_UTCTIME) 134*59c8e88eSDag-Erling Smørgrav return (-1); 135*59c8e88eSDag-Erling Smørgrav lt->tm_year = (ATOI2(p) * 100) - 1900; /* cc */ 136*59c8e88eSDag-Erling Smørgrav type = V_ASN1_GENERALIZEDTIME; 137*59c8e88eSDag-Erling Smørgrav /* FALLTHROUGH */ 138*59c8e88eSDag-Erling Smørgrav case UTCTIME_LENGTH: 139*59c8e88eSDag-Erling Smørgrav if (type == 0) { 140*59c8e88eSDag-Erling Smørgrav if (mode == V_ASN1_GENERALIZEDTIME) 141*59c8e88eSDag-Erling Smørgrav return (-1); 142*59c8e88eSDag-Erling Smørgrav type = V_ASN1_UTCTIME; 143*59c8e88eSDag-Erling Smørgrav } 144*59c8e88eSDag-Erling Smørgrav lt->tm_year += ATOI2(p); /* yy */ 145*59c8e88eSDag-Erling Smørgrav if (type == V_ASN1_UTCTIME) { 146*59c8e88eSDag-Erling Smørgrav if (lt->tm_year < 50) 147*59c8e88eSDag-Erling Smørgrav lt->tm_year += 100; 148*59c8e88eSDag-Erling Smørgrav } 149*59c8e88eSDag-Erling Smørgrav lt->tm_mon = ATOI2(p) - 1; /* mm */ 150*59c8e88eSDag-Erling Smørgrav if (lt->tm_mon < 0 || lt->tm_mon > 11) 151*59c8e88eSDag-Erling Smørgrav return (-1); 152*59c8e88eSDag-Erling Smørgrav lt->tm_mday = ATOI2(p); /* dd */ 153*59c8e88eSDag-Erling Smørgrav if (lt->tm_mday < 1 || lt->tm_mday > 31) 154*59c8e88eSDag-Erling Smørgrav return (-1); 155*59c8e88eSDag-Erling Smørgrav lt->tm_hour = ATOI2(p); /* HH */ 156*59c8e88eSDag-Erling Smørgrav if (lt->tm_hour < 0 || lt->tm_hour > 23) 157*59c8e88eSDag-Erling Smørgrav return (-1); 158*59c8e88eSDag-Erling Smørgrav lt->tm_min = ATOI2(p); /* MM */ 159*59c8e88eSDag-Erling Smørgrav if (lt->tm_min < 0 || lt->tm_min > 59) 160*59c8e88eSDag-Erling Smørgrav return (-1); 161*59c8e88eSDag-Erling Smørgrav lt->tm_sec = ATOI2(p); /* SS */ 162*59c8e88eSDag-Erling Smørgrav /* Leap second 60 is not accepted. Reconsider later? */ 163*59c8e88eSDag-Erling Smørgrav if (lt->tm_sec < 0 || lt->tm_sec > 59) 164*59c8e88eSDag-Erling Smørgrav return (-1); 165*59c8e88eSDag-Erling Smørgrav break; 166*59c8e88eSDag-Erling Smørgrav default: 167*59c8e88eSDag-Erling Smørgrav return (-1); 168*59c8e88eSDag-Erling Smørgrav } 169*59c8e88eSDag-Erling Smørgrav 170*59c8e88eSDag-Erling Smørgrav return (type); 171*59c8e88eSDag-Erling Smørgrav} 172