1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/util/dertime.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,310 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "prtypes.h" 1.9 +#include "prtime.h" 1.10 +#include "secder.h" 1.11 +#include "prlong.h" 1.12 +#include "secerr.h" 1.13 + 1.14 +#define HIDIGIT(v) (((v) / 10) + '0') 1.15 +#define LODIGIT(v) (((v) % 10) + '0') 1.16 + 1.17 +#define ISDIGIT(dig) (((dig) >= '0') && ((dig) <= '9')) 1.18 +#define CAPTURE(var,p,label) \ 1.19 +{ \ 1.20 + if (!ISDIGIT((p)[0]) || !ISDIGIT((p)[1])) goto label; \ 1.21 + (var) = ((p)[0] - '0') * 10 + ((p)[1] - '0'); \ 1.22 + p += 2; \ 1.23 +} 1.24 + 1.25 +static const PRTime January1st1 = (PRTime) LL_INIT(0xff234001U, 0x00d44000U); 1.26 +static const PRTime January1st1950 = (PRTime) LL_INIT(0xfffdc1f8U, 0x793da000U); 1.27 +static const PRTime January1st2050 = LL_INIT(0x0008f81e, 0x1b098000); 1.28 +static const PRTime January1st10000 = LL_INIT(0x0384440c, 0xcc736000); 1.29 + 1.30 +/* gmttime must contains UTC time in micro-seconds unit */ 1.31 +SECStatus 1.32 +DER_TimeToUTCTimeArena(PLArenaPool* arenaOpt, SECItem *dst, PRTime gmttime) 1.33 +{ 1.34 + PRExplodedTime printableTime; 1.35 + unsigned char *d; 1.36 + 1.37 + if ( (gmttime < January1st1950) || (gmttime >= January1st2050) ) { 1.38 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.39 + return SECFailure; 1.40 + } 1.41 + 1.42 + dst->len = 13; 1.43 + if (arenaOpt) { 1.44 + dst->data = d = (unsigned char*) PORT_ArenaAlloc(arenaOpt, dst->len); 1.45 + } else { 1.46 + dst->data = d = (unsigned char*) PORT_Alloc(dst->len); 1.47 + } 1.48 + dst->type = siUTCTime; 1.49 + if (!d) { 1.50 + return SECFailure; 1.51 + } 1.52 + 1.53 + /* Convert a PRTime to a printable format. */ 1.54 + PR_ExplodeTime(gmttime, PR_GMTParameters, &printableTime); 1.55 + 1.56 + /* The month in UTC time is base one */ 1.57 + printableTime.tm_month++; 1.58 + 1.59 + /* remove the century since it's added to the tm_year by the 1.60 + PR_ExplodeTime routine, but is not needed for UTC time */ 1.61 + printableTime.tm_year %= 100; 1.62 + 1.63 + d[0] = HIDIGIT(printableTime.tm_year); 1.64 + d[1] = LODIGIT(printableTime.tm_year); 1.65 + d[2] = HIDIGIT(printableTime.tm_month); 1.66 + d[3] = LODIGIT(printableTime.tm_month); 1.67 + d[4] = HIDIGIT(printableTime.tm_mday); 1.68 + d[5] = LODIGIT(printableTime.tm_mday); 1.69 + d[6] = HIDIGIT(printableTime.tm_hour); 1.70 + d[7] = LODIGIT(printableTime.tm_hour); 1.71 + d[8] = HIDIGIT(printableTime.tm_min); 1.72 + d[9] = LODIGIT(printableTime.tm_min); 1.73 + d[10] = HIDIGIT(printableTime.tm_sec); 1.74 + d[11] = LODIGIT(printableTime.tm_sec); 1.75 + d[12] = 'Z'; 1.76 + return SECSuccess; 1.77 +} 1.78 + 1.79 +SECStatus 1.80 +DER_TimeToUTCTime(SECItem *dst, PRTime gmttime) 1.81 +{ 1.82 + return DER_TimeToUTCTimeArena(NULL, dst, gmttime); 1.83 +} 1.84 + 1.85 +static SECStatus /* forward */ 1.86 +der_TimeStringToTime(PRTime *dst, const char *string, int generalized, 1.87 + const char **endptr); 1.88 + 1.89 +#define GEN_STRING 2 /* TimeString is a GeneralizedTime */ 1.90 +#define UTC_STRING 0 /* TimeString is a UTCTime */ 1.91 + 1.92 +/* The caller of DER_AsciiToItem MUST ENSURE that either 1.93 +** a) "string" points to a null-terminated ASCII string, or 1.94 +** b) "string" points to a buffer containing a valid UTCTime, 1.95 +** whether null terminated or not, or 1.96 +** c) "string" contains at least 19 characters, with or without null char. 1.97 +** otherwise, this function may UMR and/or crash. 1.98 +** It suffices to ensure that the input "string" is at least 17 bytes long. 1.99 +*/ 1.100 +SECStatus 1.101 +DER_AsciiToTime(PRTime *dst, const char *string) 1.102 +{ 1.103 + return der_TimeStringToTime(dst, string, UTC_STRING, NULL); 1.104 +} 1.105 + 1.106 +SECStatus 1.107 +DER_UTCTimeToTime(PRTime *dst, const SECItem *time) 1.108 +{ 1.109 + /* Minimum valid UTCTime is yymmddhhmmZ which is 11 bytes. 1.110 + ** Maximum valid UTCTime is yymmddhhmmss+0000 which is 17 bytes. 1.111 + ** 20 should be large enough for all valid encoded times. 1.112 + */ 1.113 + unsigned int i; 1.114 + char localBuf[20]; 1.115 + const char *end = NULL; 1.116 + SECStatus rv; 1.117 + 1.118 + if (!time || !time->data || time->len < 11 || time->len > 17) { 1.119 + PORT_SetError(SEC_ERROR_INVALID_TIME); 1.120 + return SECFailure; 1.121 + } 1.122 + 1.123 + for (i = 0; i < time->len; i++) { 1.124 + if (time->data[i] == '\0') { 1.125 + PORT_SetError(SEC_ERROR_INVALID_TIME); 1.126 + return SECFailure; 1.127 + } 1.128 + localBuf[i] = time->data[i]; 1.129 + } 1.130 + localBuf[i] = '\0'; 1.131 + 1.132 + rv = der_TimeStringToTime(dst, localBuf, UTC_STRING, &end); 1.133 + if (rv == SECSuccess && *end != '\0') { 1.134 + PORT_SetError(SEC_ERROR_INVALID_TIME); 1.135 + return SECFailure; 1.136 + } 1.137 + return rv; 1.138 +} 1.139 + 1.140 +/* 1.141 + gmttime must contains UTC time in micro-seconds unit. 1.142 + Note: the caller should make sure that Generalized time 1.143 + should only be used for certifiate validities after the 1.144 + year 2049. Otherwise, UTC time should be used. This routine 1.145 + does not check this case, since it can be used to encode 1.146 + certificate extension, which does not have this restriction. 1.147 + */ 1.148 +SECStatus 1.149 +DER_TimeToGeneralizedTimeArena(PLArenaPool* arenaOpt, SECItem *dst, PRTime gmttime) 1.150 +{ 1.151 + PRExplodedTime printableTime; 1.152 + unsigned char *d; 1.153 + 1.154 + if ( (gmttime<January1st1) || (gmttime>=January1st10000) ) { 1.155 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.156 + return SECFailure; 1.157 + } 1.158 + dst->len = 15; 1.159 + if (arenaOpt) { 1.160 + dst->data = d = (unsigned char*) PORT_ArenaAlloc(arenaOpt, dst->len); 1.161 + } else { 1.162 + dst->data = d = (unsigned char*) PORT_Alloc(dst->len); 1.163 + } 1.164 + dst->type = siGeneralizedTime; 1.165 + if (!d) { 1.166 + return SECFailure; 1.167 + } 1.168 + 1.169 + /* Convert a PRTime to a printable format. */ 1.170 + PR_ExplodeTime(gmttime, PR_GMTParameters, &printableTime); 1.171 + 1.172 + /* The month in Generalized time is base one */ 1.173 + printableTime.tm_month++; 1.174 + 1.175 + d[0] = (printableTime.tm_year /1000) + '0'; 1.176 + d[1] = ((printableTime.tm_year % 1000) / 100) + '0'; 1.177 + d[2] = ((printableTime.tm_year % 100) / 10) + '0'; 1.178 + d[3] = (printableTime.tm_year % 10) + '0'; 1.179 + d[4] = HIDIGIT(printableTime.tm_month); 1.180 + d[5] = LODIGIT(printableTime.tm_month); 1.181 + d[6] = HIDIGIT(printableTime.tm_mday); 1.182 + d[7] = LODIGIT(printableTime.tm_mday); 1.183 + d[8] = HIDIGIT(printableTime.tm_hour); 1.184 + d[9] = LODIGIT(printableTime.tm_hour); 1.185 + d[10] = HIDIGIT(printableTime.tm_min); 1.186 + d[11] = LODIGIT(printableTime.tm_min); 1.187 + d[12] = HIDIGIT(printableTime.tm_sec); 1.188 + d[13] = LODIGIT(printableTime.tm_sec); 1.189 + d[14] = 'Z'; 1.190 + return SECSuccess; 1.191 +} 1.192 + 1.193 +SECStatus 1.194 +DER_TimeToGeneralizedTime(SECItem *dst, PRTime gmttime) 1.195 +{ 1.196 + return DER_TimeToGeneralizedTimeArena(NULL, dst, gmttime); 1.197 +} 1.198 + 1.199 + 1.200 +SECStatus 1.201 +DER_GeneralizedTimeToTime(PRTime *dst, const SECItem *time) 1.202 +{ 1.203 + /* Minimum valid GeneralizedTime is ccyymmddhhmmZ which is 13 bytes. 1.204 + ** Maximum valid GeneralizedTime is ccyymmddhhmmss+0000 which is 19 bytes. 1.205 + ** 20 should be large enough for all valid encoded times. 1.206 + */ 1.207 + unsigned int i; 1.208 + char localBuf[20]; 1.209 + const char *end = NULL; 1.210 + SECStatus rv; 1.211 + 1.212 + if (!time || !time->data || time->len < 13 || time->len > 19) { 1.213 + PORT_SetError(SEC_ERROR_INVALID_TIME); 1.214 + return SECFailure; 1.215 + } 1.216 + 1.217 + for (i = 0; i < time->len; i++) { 1.218 + if (time->data[i] == '\0') { 1.219 + PORT_SetError(SEC_ERROR_INVALID_TIME); 1.220 + return SECFailure; 1.221 + } 1.222 + localBuf[i] = time->data[i]; 1.223 + } 1.224 + localBuf[i] = '\0'; 1.225 + 1.226 + rv = der_TimeStringToTime(dst, localBuf, GEN_STRING, &end); 1.227 + if (rv == SECSuccess && *end != '\0') { 1.228 + PORT_SetError(SEC_ERROR_INVALID_TIME); 1.229 + return SECFailure; 1.230 + } 1.231 + return rv; 1.232 +} 1.233 + 1.234 +static SECStatus 1.235 +der_TimeStringToTime(PRTime *dst, const char *string, int generalized, 1.236 + const char **endptr) 1.237 +{ 1.238 + PRExplodedTime genTime; 1.239 + long hourOff = 0, minOff = 0; 1.240 + PRUint16 century; 1.241 + char signum; 1.242 + 1.243 + if (string == NULL || dst == NULL) { 1.244 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.245 + return SECFailure; 1.246 + } 1.247 + 1.248 + /* Verify time is formatted properly and capture information */ 1.249 + memset(&genTime, 0, sizeof genTime); 1.250 + 1.251 + if (generalized == UTC_STRING) { 1.252 + CAPTURE(genTime.tm_year, string, loser); 1.253 + century = (genTime.tm_year < 50) ? 20 : 19; 1.254 + } else { 1.255 + CAPTURE(century, string, loser); 1.256 + CAPTURE(genTime.tm_year, string, loser); 1.257 + } 1.258 + genTime.tm_year += century * 100; 1.259 + 1.260 + CAPTURE(genTime.tm_month, string, loser); 1.261 + if ((genTime.tm_month == 0) || (genTime.tm_month > 12)) 1.262 + goto loser; 1.263 + 1.264 + /* NSPR month base is 0 */ 1.265 + --genTime.tm_month; 1.266 + 1.267 + CAPTURE(genTime.tm_mday, string, loser); 1.268 + if ((genTime.tm_mday == 0) || (genTime.tm_mday > 31)) 1.269 + goto loser; 1.270 + 1.271 + CAPTURE(genTime.tm_hour, string, loser); 1.272 + if (genTime.tm_hour > 23) 1.273 + goto loser; 1.274 + 1.275 + CAPTURE(genTime.tm_min, string, loser); 1.276 + if (genTime.tm_min > 59) 1.277 + goto loser; 1.278 + 1.279 + if (ISDIGIT(string[0])) { 1.280 + CAPTURE(genTime.tm_sec, string, loser); 1.281 + if (genTime.tm_sec > 59) 1.282 + goto loser; 1.283 + } 1.284 + signum = *string++; 1.285 + if (signum == '+' || signum == '-') { 1.286 + CAPTURE(hourOff, string, loser); 1.287 + if (hourOff > 23) 1.288 + goto loser; 1.289 + CAPTURE(minOff, string, loser); 1.290 + if (minOff > 59) 1.291 + goto loser; 1.292 + if (signum == '-') { 1.293 + hourOff = -hourOff; 1.294 + minOff = -minOff; 1.295 + } 1.296 + } else if (signum != 'Z') { 1.297 + goto loser; 1.298 + } 1.299 + 1.300 + if (endptr) 1.301 + *endptr = string; 1.302 + 1.303 + /* Convert the GMT offset to seconds and save it in genTime 1.304 + * for the implode time call. 1.305 + */ 1.306 + genTime.tm_params.tp_gmt_offset = (PRInt32)((hourOff * 60L + minOff) * 60L); 1.307 + *dst = PR_ImplodeTime(&genTime); 1.308 + return SECSuccess; 1.309 + 1.310 +loser: 1.311 + PORT_SetError(SEC_ERROR_INVALID_TIME); 1.312 + return SECFailure; 1.313 +}