tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

dertime.c (9589B)


      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]))     \
     18            goto label;                               \
     19        (var) = ((p)[0] - '0') * 10 + ((p)[1] - '0'); \
     20        p += 2;                                       \
     21    }
     22 
     23 static const PRTime January1st1 = PR_INT64(0xff23400100d44000);
     24 static const PRTime January1st1950 = PR_INT64(0xfffdc1f8793da000);
     25 static const PRTime January1st2050 = PR_INT64(0x0008f81e1b098000);
     26 static const PRTime January1st10000 = PR_INT64(0x0384440ccc736000);
     27 
     28 /* gmttime must contains UTC time in micro-seconds unit */
     29 SECStatus
     30 DER_TimeToUTCTimeArena(PLArenaPool *arenaOpt, SECItem *dst, PRTime gmttime)
     31 {
     32    PRExplodedTime printableTime;
     33    unsigned char *d;
     34 
     35    if ((gmttime < January1st1950) || (gmttime >= January1st2050)) {
     36        PORT_SetError(SEC_ERROR_INVALID_ARGS);
     37        return SECFailure;
     38    }
     39 
     40    dst->len = 13;
     41    if (arenaOpt) {
     42        dst->data = d = (unsigned char *)PORT_ArenaAlloc(arenaOpt, dst->len);
     43    } else {
     44        dst->data = d = (unsigned char *)PORT_Alloc(dst->len);
     45    }
     46    dst->type = siUTCTime;
     47    if (!d) {
     48        return SECFailure;
     49    }
     50 
     51    /* Convert a PRTime to a printable format.  */
     52    PR_ExplodeTime(gmttime, PR_GMTParameters, &printableTime);
     53 
     54    /* The month in UTC time is base one */
     55    printableTime.tm_month++;
     56 
     57    /* remove the century since it's added to the tm_year by the
     58       PR_ExplodeTime routine, but is not needed for UTC time */
     59    printableTime.tm_year %= 100;
     60 
     61    d[0] = HIDIGIT(printableTime.tm_year);
     62    d[1] = LODIGIT(printableTime.tm_year);
     63    d[2] = HIDIGIT(printableTime.tm_month);
     64    d[3] = LODIGIT(printableTime.tm_month);
     65    d[4] = HIDIGIT(printableTime.tm_mday);
     66    d[5] = LODIGIT(printableTime.tm_mday);
     67    d[6] = HIDIGIT(printableTime.tm_hour);
     68    d[7] = LODIGIT(printableTime.tm_hour);
     69    d[8] = HIDIGIT(printableTime.tm_min);
     70    d[9] = LODIGIT(printableTime.tm_min);
     71    d[10] = HIDIGIT(printableTime.tm_sec);
     72    d[11] = LODIGIT(printableTime.tm_sec);
     73    d[12] = 'Z';
     74    return SECSuccess;
     75 }
     76 
     77 SECStatus
     78 DER_TimeToUTCTime(SECItem *dst, PRTime gmttime)
     79 {
     80    return DER_TimeToUTCTimeArena(NULL, dst, gmttime);
     81 }
     82 
     83 static SECStatus /* forward */
     84 der_TimeStringToTime(PRTime *dst, const char *string, int generalized,
     85                     const char **endptr);
     86 
     87 #define GEN_STRING 2 /* TimeString is a GeneralizedTime */
     88 #define UTC_STRING 0 /* TimeString is a UTCTime         */
     89 
     90 /* The caller of DER_AsciiToItem MUST ENSURE that either
     91 ** a) "string" points to a null-terminated ASCII string, or
     92 ** b) "string" points to a buffer containing a valid UTCTime,
     93 **     whether null terminated or not, or
     94 ** c) "string" contains at least 19 characters, with or without null char.
     95 ** otherwise, this function may UMR and/or crash.
     96 ** It suffices to ensure that the input "string" is at least 17 bytes long.
     97 */
     98 SECStatus
     99 DER_AsciiToTime(PRTime *dst, const char *string)
    100 {
    101    return der_TimeStringToTime(dst, string, UTC_STRING, NULL);
    102 }
    103 
    104 SECStatus
    105 DER_UTCTimeToTime(PRTime *dst, const SECItem *time)
    106 {
    107    /* Minimum valid UTCTime is yymmddhhmmZ       which is 11 bytes.
    108    ** Maximum valid UTCTime is yymmddhhmmss+0000 which is 17 bytes.
    109    ** 20 should be large enough for all valid encoded times.
    110    */
    111    unsigned int i;
    112    char localBuf[20];
    113    const char *end = NULL;
    114    SECStatus rv;
    115 
    116    if (!time || !time->data || time->len < 11 || time->len > 17) {
    117        PORT_SetError(SEC_ERROR_INVALID_TIME);
    118        return SECFailure;
    119    }
    120 
    121    for (i = 0; i < time->len; i++) {
    122        if (time->data[i] == '\0') {
    123            PORT_SetError(SEC_ERROR_INVALID_TIME);
    124            return SECFailure;
    125        }
    126        localBuf[i] = time->data[i];
    127    }
    128    localBuf[i] = '\0';
    129 
    130    rv = der_TimeStringToTime(dst, localBuf, UTC_STRING, &end);
    131    if (rv == SECSuccess && *end != '\0') {
    132        PORT_SetError(SEC_ERROR_INVALID_TIME);
    133        return SECFailure;
    134    }
    135    return rv;
    136 }
    137 
    138 /*
    139   gmttime must contains UTC time in micro-seconds unit.
    140   Note: the caller should make sure that Generalized time
    141   should only be used for certifiate validities after the
    142   year 2049.  Otherwise, UTC time should be used.  This routine
    143   does not check this case, since it can be used to encode
    144   certificate extension, which does not have this restriction.
    145 */
    146 SECStatus
    147 DER_TimeToGeneralizedTimeArena(PLArenaPool *arenaOpt, SECItem *dst, PRTime gmttime)
    148 {
    149    PRExplodedTime printableTime;
    150    unsigned char *d;
    151 
    152    if ((gmttime < January1st1) || (gmttime >= January1st10000)) {
    153        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    154        return SECFailure;
    155    }
    156    dst->len = 15;
    157    if (arenaOpt) {
    158        dst->data = d = (unsigned char *)PORT_ArenaAlloc(arenaOpt, dst->len);
    159    } else {
    160        dst->data = d = (unsigned char *)PORT_Alloc(dst->len);
    161    }
    162    dst->type = siGeneralizedTime;
    163    if (!d) {
    164        return SECFailure;
    165    }
    166 
    167    /* Convert a PRTime to a printable format.  */
    168    PR_ExplodeTime(gmttime, PR_GMTParameters, &printableTime);
    169 
    170    /* The month in Generalized time is base one */
    171    printableTime.tm_month++;
    172 
    173    d[0] = (printableTime.tm_year / 1000) + '0';
    174    d[1] = ((printableTime.tm_year % 1000) / 100) + '0';
    175    d[2] = ((printableTime.tm_year % 100) / 10) + '0';
    176    d[3] = (printableTime.tm_year % 10) + '0';
    177    d[4] = HIDIGIT(printableTime.tm_month);
    178    d[5] = LODIGIT(printableTime.tm_month);
    179    d[6] = HIDIGIT(printableTime.tm_mday);
    180    d[7] = LODIGIT(printableTime.tm_mday);
    181    d[8] = HIDIGIT(printableTime.tm_hour);
    182    d[9] = LODIGIT(printableTime.tm_hour);
    183    d[10] = HIDIGIT(printableTime.tm_min);
    184    d[11] = LODIGIT(printableTime.tm_min);
    185    d[12] = HIDIGIT(printableTime.tm_sec);
    186    d[13] = LODIGIT(printableTime.tm_sec);
    187    d[14] = 'Z';
    188    return SECSuccess;
    189 }
    190 
    191 SECStatus
    192 DER_TimeToGeneralizedTime(SECItem *dst, PRTime gmttime)
    193 {
    194    return DER_TimeToGeneralizedTimeArena(NULL, dst, gmttime);
    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 }