Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | #include "prtypes.h" |
michael@0 | 6 | #include "prtime.h" |
michael@0 | 7 | #include "secder.h" |
michael@0 | 8 | #include "prlong.h" |
michael@0 | 9 | #include "secerr.h" |
michael@0 | 10 | |
michael@0 | 11 | #define HIDIGIT(v) (((v) / 10) + '0') |
michael@0 | 12 | #define LODIGIT(v) (((v) % 10) + '0') |
michael@0 | 13 | |
michael@0 | 14 | #define ISDIGIT(dig) (((dig) >= '0') && ((dig) <= '9')) |
michael@0 | 15 | #define CAPTURE(var,p,label) \ |
michael@0 | 16 | { \ |
michael@0 | 17 | if (!ISDIGIT((p)[0]) || !ISDIGIT((p)[1])) goto label; \ |
michael@0 | 18 | (var) = ((p)[0] - '0') * 10 + ((p)[1] - '0'); \ |
michael@0 | 19 | p += 2; \ |
michael@0 | 20 | } |
michael@0 | 21 | |
michael@0 | 22 | static const PRTime January1st1 = (PRTime) LL_INIT(0xff234001U, 0x00d44000U); |
michael@0 | 23 | static const PRTime January1st1950 = (PRTime) LL_INIT(0xfffdc1f8U, 0x793da000U); |
michael@0 | 24 | static const PRTime January1st2050 = LL_INIT(0x0008f81e, 0x1b098000); |
michael@0 | 25 | static const PRTime January1st10000 = LL_INIT(0x0384440c, 0xcc736000); |
michael@0 | 26 | |
michael@0 | 27 | /* gmttime must contains UTC time in micro-seconds unit */ |
michael@0 | 28 | SECStatus |
michael@0 | 29 | DER_TimeToUTCTimeArena(PLArenaPool* arenaOpt, SECItem *dst, PRTime gmttime) |
michael@0 | 30 | { |
michael@0 | 31 | PRExplodedTime printableTime; |
michael@0 | 32 | unsigned char *d; |
michael@0 | 33 | |
michael@0 | 34 | if ( (gmttime < January1st1950) || (gmttime >= January1st2050) ) { |
michael@0 | 35 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 36 | return SECFailure; |
michael@0 | 37 | } |
michael@0 | 38 | |
michael@0 | 39 | dst->len = 13; |
michael@0 | 40 | if (arenaOpt) { |
michael@0 | 41 | dst->data = d = (unsigned char*) PORT_ArenaAlloc(arenaOpt, dst->len); |
michael@0 | 42 | } else { |
michael@0 | 43 | dst->data = d = (unsigned char*) PORT_Alloc(dst->len); |
michael@0 | 44 | } |
michael@0 | 45 | dst->type = siUTCTime; |
michael@0 | 46 | if (!d) { |
michael@0 | 47 | return SECFailure; |
michael@0 | 48 | } |
michael@0 | 49 | |
michael@0 | 50 | /* Convert a PRTime to a printable format. */ |
michael@0 | 51 | PR_ExplodeTime(gmttime, PR_GMTParameters, &printableTime); |
michael@0 | 52 | |
michael@0 | 53 | /* The month in UTC time is base one */ |
michael@0 | 54 | printableTime.tm_month++; |
michael@0 | 55 | |
michael@0 | 56 | /* remove the century since it's added to the tm_year by the |
michael@0 | 57 | PR_ExplodeTime routine, but is not needed for UTC time */ |
michael@0 | 58 | printableTime.tm_year %= 100; |
michael@0 | 59 | |
michael@0 | 60 | d[0] = HIDIGIT(printableTime.tm_year); |
michael@0 | 61 | d[1] = LODIGIT(printableTime.tm_year); |
michael@0 | 62 | d[2] = HIDIGIT(printableTime.tm_month); |
michael@0 | 63 | d[3] = LODIGIT(printableTime.tm_month); |
michael@0 | 64 | d[4] = HIDIGIT(printableTime.tm_mday); |
michael@0 | 65 | d[5] = LODIGIT(printableTime.tm_mday); |
michael@0 | 66 | d[6] = HIDIGIT(printableTime.tm_hour); |
michael@0 | 67 | d[7] = LODIGIT(printableTime.tm_hour); |
michael@0 | 68 | d[8] = HIDIGIT(printableTime.tm_min); |
michael@0 | 69 | d[9] = LODIGIT(printableTime.tm_min); |
michael@0 | 70 | d[10] = HIDIGIT(printableTime.tm_sec); |
michael@0 | 71 | d[11] = LODIGIT(printableTime.tm_sec); |
michael@0 | 72 | d[12] = 'Z'; |
michael@0 | 73 | return SECSuccess; |
michael@0 | 74 | } |
michael@0 | 75 | |
michael@0 | 76 | SECStatus |
michael@0 | 77 | DER_TimeToUTCTime(SECItem *dst, PRTime gmttime) |
michael@0 | 78 | { |
michael@0 | 79 | return DER_TimeToUTCTimeArena(NULL, dst, gmttime); |
michael@0 | 80 | } |
michael@0 | 81 | |
michael@0 | 82 | static SECStatus /* forward */ |
michael@0 | 83 | der_TimeStringToTime(PRTime *dst, const char *string, int generalized, |
michael@0 | 84 | const char **endptr); |
michael@0 | 85 | |
michael@0 | 86 | #define GEN_STRING 2 /* TimeString is a GeneralizedTime */ |
michael@0 | 87 | #define UTC_STRING 0 /* TimeString is a UTCTime */ |
michael@0 | 88 | |
michael@0 | 89 | /* The caller of DER_AsciiToItem MUST ENSURE that either |
michael@0 | 90 | ** a) "string" points to a null-terminated ASCII string, or |
michael@0 | 91 | ** b) "string" points to a buffer containing a valid UTCTime, |
michael@0 | 92 | ** whether null terminated or not, or |
michael@0 | 93 | ** c) "string" contains at least 19 characters, with or without null char. |
michael@0 | 94 | ** otherwise, this function may UMR and/or crash. |
michael@0 | 95 | ** It suffices to ensure that the input "string" is at least 17 bytes long. |
michael@0 | 96 | */ |
michael@0 | 97 | SECStatus |
michael@0 | 98 | DER_AsciiToTime(PRTime *dst, const char *string) |
michael@0 | 99 | { |
michael@0 | 100 | return der_TimeStringToTime(dst, string, UTC_STRING, NULL); |
michael@0 | 101 | } |
michael@0 | 102 | |
michael@0 | 103 | SECStatus |
michael@0 | 104 | DER_UTCTimeToTime(PRTime *dst, const SECItem *time) |
michael@0 | 105 | { |
michael@0 | 106 | /* Minimum valid UTCTime is yymmddhhmmZ which is 11 bytes. |
michael@0 | 107 | ** Maximum valid UTCTime is yymmddhhmmss+0000 which is 17 bytes. |
michael@0 | 108 | ** 20 should be large enough for all valid encoded times. |
michael@0 | 109 | */ |
michael@0 | 110 | unsigned int i; |
michael@0 | 111 | char localBuf[20]; |
michael@0 | 112 | const char *end = NULL; |
michael@0 | 113 | SECStatus rv; |
michael@0 | 114 | |
michael@0 | 115 | if (!time || !time->data || time->len < 11 || time->len > 17) { |
michael@0 | 116 | PORT_SetError(SEC_ERROR_INVALID_TIME); |
michael@0 | 117 | return SECFailure; |
michael@0 | 118 | } |
michael@0 | 119 | |
michael@0 | 120 | for (i = 0; i < time->len; i++) { |
michael@0 | 121 | if (time->data[i] == '\0') { |
michael@0 | 122 | PORT_SetError(SEC_ERROR_INVALID_TIME); |
michael@0 | 123 | return SECFailure; |
michael@0 | 124 | } |
michael@0 | 125 | localBuf[i] = time->data[i]; |
michael@0 | 126 | } |
michael@0 | 127 | localBuf[i] = '\0'; |
michael@0 | 128 | |
michael@0 | 129 | rv = der_TimeStringToTime(dst, localBuf, UTC_STRING, &end); |
michael@0 | 130 | if (rv == SECSuccess && *end != '\0') { |
michael@0 | 131 | PORT_SetError(SEC_ERROR_INVALID_TIME); |
michael@0 | 132 | return SECFailure; |
michael@0 | 133 | } |
michael@0 | 134 | return rv; |
michael@0 | 135 | } |
michael@0 | 136 | |
michael@0 | 137 | /* |
michael@0 | 138 | gmttime must contains UTC time in micro-seconds unit. |
michael@0 | 139 | Note: the caller should make sure that Generalized time |
michael@0 | 140 | should only be used for certifiate validities after the |
michael@0 | 141 | year 2049. Otherwise, UTC time should be used. This routine |
michael@0 | 142 | does not check this case, since it can be used to encode |
michael@0 | 143 | certificate extension, which does not have this restriction. |
michael@0 | 144 | */ |
michael@0 | 145 | SECStatus |
michael@0 | 146 | DER_TimeToGeneralizedTimeArena(PLArenaPool* arenaOpt, SECItem *dst, PRTime gmttime) |
michael@0 | 147 | { |
michael@0 | 148 | PRExplodedTime printableTime; |
michael@0 | 149 | unsigned char *d; |
michael@0 | 150 | |
michael@0 | 151 | if ( (gmttime<January1st1) || (gmttime>=January1st10000) ) { |
michael@0 | 152 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 153 | return SECFailure; |
michael@0 | 154 | } |
michael@0 | 155 | dst->len = 15; |
michael@0 | 156 | if (arenaOpt) { |
michael@0 | 157 | dst->data = d = (unsigned char*) PORT_ArenaAlloc(arenaOpt, dst->len); |
michael@0 | 158 | } else { |
michael@0 | 159 | dst->data = d = (unsigned char*) PORT_Alloc(dst->len); |
michael@0 | 160 | } |
michael@0 | 161 | dst->type = siGeneralizedTime; |
michael@0 | 162 | if (!d) { |
michael@0 | 163 | return SECFailure; |
michael@0 | 164 | } |
michael@0 | 165 | |
michael@0 | 166 | /* Convert a PRTime to a printable format. */ |
michael@0 | 167 | PR_ExplodeTime(gmttime, PR_GMTParameters, &printableTime); |
michael@0 | 168 | |
michael@0 | 169 | /* The month in Generalized time is base one */ |
michael@0 | 170 | printableTime.tm_month++; |
michael@0 | 171 | |
michael@0 | 172 | d[0] = (printableTime.tm_year /1000) + '0'; |
michael@0 | 173 | d[1] = ((printableTime.tm_year % 1000) / 100) + '0'; |
michael@0 | 174 | d[2] = ((printableTime.tm_year % 100) / 10) + '0'; |
michael@0 | 175 | d[3] = (printableTime.tm_year % 10) + '0'; |
michael@0 | 176 | d[4] = HIDIGIT(printableTime.tm_month); |
michael@0 | 177 | d[5] = LODIGIT(printableTime.tm_month); |
michael@0 | 178 | d[6] = HIDIGIT(printableTime.tm_mday); |
michael@0 | 179 | d[7] = LODIGIT(printableTime.tm_mday); |
michael@0 | 180 | d[8] = HIDIGIT(printableTime.tm_hour); |
michael@0 | 181 | d[9] = LODIGIT(printableTime.tm_hour); |
michael@0 | 182 | d[10] = HIDIGIT(printableTime.tm_min); |
michael@0 | 183 | d[11] = LODIGIT(printableTime.tm_min); |
michael@0 | 184 | d[12] = HIDIGIT(printableTime.tm_sec); |
michael@0 | 185 | d[13] = LODIGIT(printableTime.tm_sec); |
michael@0 | 186 | d[14] = 'Z'; |
michael@0 | 187 | return SECSuccess; |
michael@0 | 188 | } |
michael@0 | 189 | |
michael@0 | 190 | SECStatus |
michael@0 | 191 | DER_TimeToGeneralizedTime(SECItem *dst, PRTime gmttime) |
michael@0 | 192 | { |
michael@0 | 193 | return DER_TimeToGeneralizedTimeArena(NULL, dst, gmttime); |
michael@0 | 194 | } |
michael@0 | 195 | |
michael@0 | 196 | |
michael@0 | 197 | SECStatus |
michael@0 | 198 | DER_GeneralizedTimeToTime(PRTime *dst, const SECItem *time) |
michael@0 | 199 | { |
michael@0 | 200 | /* Minimum valid GeneralizedTime is ccyymmddhhmmZ which is 13 bytes. |
michael@0 | 201 | ** Maximum valid GeneralizedTime is ccyymmddhhmmss+0000 which is 19 bytes. |
michael@0 | 202 | ** 20 should be large enough for all valid encoded times. |
michael@0 | 203 | */ |
michael@0 | 204 | unsigned int i; |
michael@0 | 205 | char localBuf[20]; |
michael@0 | 206 | const char *end = NULL; |
michael@0 | 207 | SECStatus rv; |
michael@0 | 208 | |
michael@0 | 209 | if (!time || !time->data || time->len < 13 || time->len > 19) { |
michael@0 | 210 | PORT_SetError(SEC_ERROR_INVALID_TIME); |
michael@0 | 211 | return SECFailure; |
michael@0 | 212 | } |
michael@0 | 213 | |
michael@0 | 214 | for (i = 0; i < time->len; i++) { |
michael@0 | 215 | if (time->data[i] == '\0') { |
michael@0 | 216 | PORT_SetError(SEC_ERROR_INVALID_TIME); |
michael@0 | 217 | return SECFailure; |
michael@0 | 218 | } |
michael@0 | 219 | localBuf[i] = time->data[i]; |
michael@0 | 220 | } |
michael@0 | 221 | localBuf[i] = '\0'; |
michael@0 | 222 | |
michael@0 | 223 | rv = der_TimeStringToTime(dst, localBuf, GEN_STRING, &end); |
michael@0 | 224 | if (rv == SECSuccess && *end != '\0') { |
michael@0 | 225 | PORT_SetError(SEC_ERROR_INVALID_TIME); |
michael@0 | 226 | return SECFailure; |
michael@0 | 227 | } |
michael@0 | 228 | return rv; |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | static SECStatus |
michael@0 | 232 | der_TimeStringToTime(PRTime *dst, const char *string, int generalized, |
michael@0 | 233 | const char **endptr) |
michael@0 | 234 | { |
michael@0 | 235 | PRExplodedTime genTime; |
michael@0 | 236 | long hourOff = 0, minOff = 0; |
michael@0 | 237 | PRUint16 century; |
michael@0 | 238 | char signum; |
michael@0 | 239 | |
michael@0 | 240 | if (string == NULL || dst == NULL) { |
michael@0 | 241 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 242 | return SECFailure; |
michael@0 | 243 | } |
michael@0 | 244 | |
michael@0 | 245 | /* Verify time is formatted properly and capture information */ |
michael@0 | 246 | memset(&genTime, 0, sizeof genTime); |
michael@0 | 247 | |
michael@0 | 248 | if (generalized == UTC_STRING) { |
michael@0 | 249 | CAPTURE(genTime.tm_year, string, loser); |
michael@0 | 250 | century = (genTime.tm_year < 50) ? 20 : 19; |
michael@0 | 251 | } else { |
michael@0 | 252 | CAPTURE(century, string, loser); |
michael@0 | 253 | CAPTURE(genTime.tm_year, string, loser); |
michael@0 | 254 | } |
michael@0 | 255 | genTime.tm_year += century * 100; |
michael@0 | 256 | |
michael@0 | 257 | CAPTURE(genTime.tm_month, string, loser); |
michael@0 | 258 | if ((genTime.tm_month == 0) || (genTime.tm_month > 12)) |
michael@0 | 259 | goto loser; |
michael@0 | 260 | |
michael@0 | 261 | /* NSPR month base is 0 */ |
michael@0 | 262 | --genTime.tm_month; |
michael@0 | 263 | |
michael@0 | 264 | CAPTURE(genTime.tm_mday, string, loser); |
michael@0 | 265 | if ((genTime.tm_mday == 0) || (genTime.tm_mday > 31)) |
michael@0 | 266 | goto loser; |
michael@0 | 267 | |
michael@0 | 268 | CAPTURE(genTime.tm_hour, string, loser); |
michael@0 | 269 | if (genTime.tm_hour > 23) |
michael@0 | 270 | goto loser; |
michael@0 | 271 | |
michael@0 | 272 | CAPTURE(genTime.tm_min, string, loser); |
michael@0 | 273 | if (genTime.tm_min > 59) |
michael@0 | 274 | goto loser; |
michael@0 | 275 | |
michael@0 | 276 | if (ISDIGIT(string[0])) { |
michael@0 | 277 | CAPTURE(genTime.tm_sec, string, loser); |
michael@0 | 278 | if (genTime.tm_sec > 59) |
michael@0 | 279 | goto loser; |
michael@0 | 280 | } |
michael@0 | 281 | signum = *string++; |
michael@0 | 282 | if (signum == '+' || signum == '-') { |
michael@0 | 283 | CAPTURE(hourOff, string, loser); |
michael@0 | 284 | if (hourOff > 23) |
michael@0 | 285 | goto loser; |
michael@0 | 286 | CAPTURE(minOff, string, loser); |
michael@0 | 287 | if (minOff > 59) |
michael@0 | 288 | goto loser; |
michael@0 | 289 | if (signum == '-') { |
michael@0 | 290 | hourOff = -hourOff; |
michael@0 | 291 | minOff = -minOff; |
michael@0 | 292 | } |
michael@0 | 293 | } else if (signum != 'Z') { |
michael@0 | 294 | goto loser; |
michael@0 | 295 | } |
michael@0 | 296 | |
michael@0 | 297 | if (endptr) |
michael@0 | 298 | *endptr = string; |
michael@0 | 299 | |
michael@0 | 300 | /* Convert the GMT offset to seconds and save it in genTime |
michael@0 | 301 | * for the implode time call. |
michael@0 | 302 | */ |
michael@0 | 303 | genTime.tm_params.tp_gmt_offset = (PRInt32)((hourOff * 60L + minOff) * 60L); |
michael@0 | 304 | *dst = PR_ImplodeTime(&genTime); |
michael@0 | 305 | return SECSuccess; |
michael@0 | 306 | |
michael@0 | 307 | loser: |
michael@0 | 308 | PORT_SetError(SEC_ERROR_INVALID_TIME); |
michael@0 | 309 | return SECFailure; |
michael@0 | 310 | } |