security/nss/lib/util/dertime.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     5 #include "prtypes.h"
     6 #include "prtime.h"
     7 #include "secder.h"
     8 #include "prlong.h"
     9 #include "secerr.h"
    11 #define HIDIGIT(v) (((v) / 10) + '0')
    12 #define LODIGIT(v) (((v) % 10) + '0')
    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 }
    22 static const PRTime January1st1     = (PRTime) LL_INIT(0xff234001U, 0x00d44000U);
    23 static const PRTime January1st1950  = (PRTime) LL_INIT(0xfffdc1f8U, 0x793da000U);
    24 static const PRTime January1st2050  = LL_INIT(0x0008f81e, 0x1b098000);
    25 static const PRTime January1st10000 = LL_INIT(0x0384440c, 0xcc736000);
    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;
    34     if ( (gmttime < January1st1950) || (gmttime >= January1st2050) ) {
    35         PORT_SetError(SEC_ERROR_INVALID_ARGS);
    36         return SECFailure;
    37     }
    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     }
    50     /* Convert a PRTime to a printable format.  */
    51     PR_ExplodeTime(gmttime, PR_GMTParameters, &printableTime);
    53     /* The month in UTC time is base one */
    54     printableTime.tm_month++;
    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; 
    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 }
    76 SECStatus
    77 DER_TimeToUTCTime(SECItem *dst, PRTime gmttime)
    78 {
    79     return DER_TimeToUTCTimeArena(NULL, dst, gmttime);
    80 }
    82 static SECStatus /* forward */
    83 der_TimeStringToTime(PRTime *dst, const char *string, int generalized,
    84                      const char **endptr);
    86 #define GEN_STRING 2 /* TimeString is a GeneralizedTime */
    87 #define UTC_STRING 0 /* TimeString is a UTCTime         */
    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 }
   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;
   115     if (!time || !time->data || time->len < 11 || time->len > 17) {
   116 	PORT_SetError(SEC_ERROR_INVALID_TIME);
   117 	return SECFailure;
   118     }
   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';
   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 }
   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 gmttime)
   147 {
   148     PRExplodedTime printableTime;
   149     unsigned char *d;
   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     }
   166     /* Convert a PRTime to a printable format.  */
   167     PR_ExplodeTime(gmttime, PR_GMTParameters, &printableTime);
   169     /* The month in Generalized time is base one */
   170     printableTime.tm_month++;
   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 }
   190 SECStatus
   191 DER_TimeToGeneralizedTime(SECItem *dst, PRTime gmttime)
   192 {
   193     return DER_TimeToGeneralizedTimeArena(NULL, dst, gmttime);
   194 }
   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;
   209     if (!time || !time->data || time->len < 13 || time->len > 19) {
   210 	PORT_SetError(SEC_ERROR_INVALID_TIME);
   211 	return SECFailure;
   212     }
   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';
   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 }
   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;
   240     if (string == NULL || dst == NULL) {
   241 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   242 	return SECFailure;
   243     }
   245     /* Verify time is formatted properly and capture information */
   246     memset(&genTime, 0, sizeof genTime);
   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;
   257     CAPTURE(genTime.tm_month, string, loser);
   258     if ((genTime.tm_month == 0) || (genTime.tm_month > 12)) 
   259     	goto loser;
   261     /* NSPR month base is 0 */
   262     --genTime.tm_month;
   264     CAPTURE(genTime.tm_mday, string, loser);
   265     if ((genTime.tm_mday == 0) || (genTime.tm_mday > 31)) 
   266     	goto loser;
   268     CAPTURE(genTime.tm_hour, string, loser);
   269     if (genTime.tm_hour > 23) 
   270     	goto loser;
   272     CAPTURE(genTime.tm_min, string, loser);
   273     if (genTime.tm_min > 59) 
   274     	goto loser;
   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     }
   297     if (endptr)
   298     	*endptr = string;
   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;
   307 loser:
   308     PORT_SetError(SEC_ERROR_INVALID_TIME);
   309     return SECFailure;
   310 }

mercurial