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