+++ /dev/null
-/*
- * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved.
- *
- * The contents of this file constitute Original Code as defined in and are
- * subject to the Apple Public Source License Version 1.2 (the 'License').
- * You may not use this file except in compliance with the License. Please obtain
- * a copy of the License at http://www.apple.com/publicsource and read it before
- * using this file.
- *
- * This Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
- * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
- * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
- * specific language governing rights and limitations under the License.
- */
-
-
-/*
- * tpTime.c - cert related time functions
- *
- */
-
-#include "tpTime.h"
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <stdbool.h>
-
-/*
- * Given a string containing either a UTC-style or "generalized time"
- * time string, convert to a CFDateRef. Returns nonzero on
- * error.
- */
-int timeStringToCfDate(
- const char *str,
- unsigned len,
- CFDateRef *cfDate)
-{
- char szTemp[5];
- bool isUtc = false; // 2-digit year
- bool isLocal = false; // trailing timezone offset
- bool isCssmTime = false; // no trailing 'Z'
- bool noSeconds = false;
- int x;
- unsigned i;
- char *cp;
- CFGregorianDate gd;
- CFTimeZoneRef timeZone;
- CFTimeInterval gmtOff = 0;
-
- if((str == NULL) || (len == 0) || (cfDate == NULL)) {
- return 1;
- }
-
- /* tolerate NULL terminated or not */
- if(str[len - 1] == '\0') {
- len--;
- }
- switch(len) {
- case UTC_TIME_NOSEC_LEN: // 2-digit year, no seconds, not y2K compliant
- isUtc = true;
- noSeconds = true;
- break;
- case UTC_TIME_STRLEN: // 2-digit year, not Y2K compliant
- isUtc = true;
- break;
- case CSSM_TIME_STRLEN:
- isCssmTime = true;
- break;
- case GENERALIZED_TIME_STRLEN: // 4-digit year
- break;
- case LOCALIZED_UTC_TIME_STRLEN: // "YYMMDDhhmmssThhmm" (where T=[+,-])
- isUtc = 1;
- // deliberate fallthrough
- case LOCALIZED_TIME_STRLEN: // "YYYYMMDDhhmmssThhmm" (where T=[+,-])
- isLocal = 1;
- break;
- default: // unknown format
- return 1;
- }
-
- cp = (char *)str;
-
- /* check that all characters except last (or timezone indicator, if localized) are digits */
- for(i=0; i<(len - 1); i++) {
- if ( !(isdigit(cp[i])) )
- if ( !isLocal || !(cp[i]=='+' || cp[i]=='-') )
- return 1;
- }
-
- /* check last character is a 'Z' or digit as appropriate */
- if(isCssmTime || isLocal) {
- if(!isdigit(cp[len - 1])) {
- return 1;
- }
- }
- else {
- if(cp[len - 1] != 'Z' ) {
- return 1;
- }
- }
-
- /* YEAR */
- szTemp[0] = *cp++;
- szTemp[1] = *cp++;
- if(!isUtc) {
- /* two more digits */
- szTemp[2] = *cp++;
- szTemp[3] = *cp++;
- szTemp[4] = '\0';
- }
- else {
- szTemp[2] = '\0';
- }
- x = atoi( szTemp );
- if(isUtc) {
- /*
- * 2-digit year.
- * 0 <= year < 50 : assume century 21
- * 50 <= year < 70 : illegal per PKIX
- * ...though we allow this as of 10/10/02...dmitch
- * 70 < year <= 99 : assume century 20
- */
- if(x < 50) {
- x += 2000;
- }
- /*
- else if(x < 70) {
- return 1;
- }
- */
- else {
- /* century 20 */
- x += 1900;
- }
- }
- gd.year = x;
-
- /* MONTH */
- szTemp[0] = *cp++;
- szTemp[1] = *cp++;
- szTemp[2] = '\0';
- x = atoi( szTemp );
- /* in the string, months are from 1 to 12 */
- if((x > 12) || (x <= 0)) {
- return 1;
- }
- gd.month = x;
-
- /* DAY */
- szTemp[0] = *cp++;
- szTemp[1] = *cp++;
- szTemp[2] = '\0';
- x = atoi( szTemp );
- /* 1..31 in both formats */
- if((x > 31) || (x <= 0)) {
- return 1;
- }
- gd.day = x;
-
- /* HOUR */
- szTemp[0] = *cp++;
- szTemp[1] = *cp++;
- szTemp[2] = '\0';
- x = atoi( szTemp );
- if((x > 23) || (x < 0)) {
- return 1;
- }
- gd.hour = x;
-
- /* MINUTE */
- szTemp[0] = *cp++;
- szTemp[1] = *cp++;
- szTemp[2] = '\0';
- x = atoi( szTemp );
- if((x > 59) || (x < 0)) {
- return 1;
- }
- gd.minute = x;
-
- /* SECOND */
- if(noSeconds) {
- gd.second = 0;
- }
- else {
- szTemp[0] = *cp++;
- szTemp[1] = *cp++;
- szTemp[2] = '\0';
- x = atoi( szTemp );
- if((x > 59) || (x < 0)) {
- return 1;
- }
- gd.second = x;
- }
-
- if (isLocal) {
- /* ZONE INDICATOR */
- switch(*cp++) {
- case '+':
- gmtOff = 1;
- break;
- case '-':
- gmtOff = -1;
- break;
- default:
- return 1;
- }
- /* ZONE HH OFFSET */
- szTemp[0] = *cp++;
- szTemp[1] = *cp++;
- szTemp[2] = '\0';
- x = atoi( szTemp ) * 60 * 60;
- gmtOff *= x;
- /* ZONE MM OFFSET */
- szTemp[0] = *cp++;
- szTemp[1] = *cp++;
- szTemp[2] = '\0';
- x = atoi( szTemp ) * 60;
- if(gmtOff < 0) {
- gmtOff -= x;
- }
- else {
- gmtOff += x;
- }
- }
- timeZone = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, gmtOff);
- if (!timeZone) {
- return 1;
- }
- *cfDate = CFDateCreate(NULL, CFGregorianDateGetAbsoluteTime(gd, timeZone));
- CFRelease(timeZone);
- return 0;
-}
-
-/*
- * Compare two times. Assumes they're both in GMT. Returns:
- * -1 if t1 < t2
- * 0 if t1 == t2
- * 1 if t1 > t2
- */
-int compareTimes(
- CFDateRef t1,
- CFDateRef t2)
-{
- switch(CFDateCompare(t1, t2, NULL)) {
- case kCFCompareLessThan:
- return -1;
- case kCFCompareEqualTo:
- return 0;
- case kCFCompareGreaterThan:
- return 1;
- }
- /* NOT REACHED */
- assert(0);
- return 0;
-}
-
-/*
- * Create a time string, in either UTC (2-digit) or or Generalized (4-digit)
- * year format. Caller mallocs the output string whose length is at least
- * (UTC_TIME_STRLEN+1), (GENERALIZED_TIME_STRLEN+1), or (CSSM_TIME_STRLEN+1)
- * respectively. Caller must hold tpTimeLock.
- */
-void timeAtNowPlus(unsigned secFromNow,
- TpTimeSpec timeSpec,
- char *outStr)
-{
- struct tm utc;
- time_t baseTime;
-
- baseTime = time(NULL);
- baseTime += (time_t)secFromNow;
- utc = *gmtime(&baseTime);
-
- switch(timeSpec) {
- case TIME_UTC:
- /* UTC - 2 year digits - code which parses this assumes that
- * (2-digit) years between 0 and 49 are in century 21 */
- if(utc.tm_year >= 100) {
- utc.tm_year -= 100;
- }
- sprintf(outStr, "%02d%02d%02d%02d%02d%02dZ",
- utc.tm_year /* + 1900 */, utc.tm_mon + 1,
- utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec);
- break;
- case TIME_GEN:
- sprintf(outStr, "%04d%02d%02d%02d%02d%02dZ",
- /* note year is relative to 1900, hopefully it'll have
- * four valid digits! */
- utc.tm_year + 1900, utc.tm_mon + 1,
- utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec);
- break;
- case TIME_CSSM:
- sprintf(outStr, "%04d%02d%02d%02d%02d%02d",
- /* note year is relative to 1900, hopefully it'll have
- * four valid digits! */
- utc.tm_year + 1900, utc.tm_mon + 1,
- utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec);
- break;
- }
-}
-
-/*
- * Convert a time string, which can be in any of three forms (UTC,
- * generalized, or CSSM_TIMESTRING) into a CSSM_TIMESTRING. Caller
- * mallocs the result, which must be at least (CSSM_TIME_STRLEN+1) bytes.
- * Returns nonzero if incoming time string is badly formed.
- */
-int tpTimeToCssmTimestring(
- const char *inStr, // not necessarily NULL terminated
- unsigned inStrLen, // not including possible NULL
- char *outTime)
-{
- if((inStrLen == 0) || (inStr == NULL)) {
- return 1;
- }
- outTime[0] = '\0';
- switch(inStrLen) {
- case UTC_TIME_STRLEN:
- {
- /* infer century and prepend to output */
- char tmp[3];
- int year;
- tmp[0] = inStr[0];
- tmp[1] = inStr[1];
- tmp[2] = '\0';
- year = atoi(tmp);
-
- /*
- * 0 <= year < 50 : assume century 21
- * 50 <= year < 70 : illegal per PKIX
- * 70 < year <= 99 : assume century 20
- */
- if(year < 50) {
- /* century 21 */
- strcpy(outTime, "20");
- }
- else if(year < 70) {
- return 1;
- }
- else {
- /* century 20 */
- strcpy(outTime, "19");
- }
- memmove(outTime + 2, inStr, inStrLen - 1); // don't copy the Z
- break;
- }
- case CSSM_TIME_STRLEN:
- memmove(outTime, inStr, inStrLen); // trivial case
- break;
- case GENERALIZED_TIME_STRLEN:
- memmove(outTime, inStr, inStrLen - 1); // don't copy the Z
- break;
-
- default:
- return 1;
- }
- outTime[CSSM_TIME_STRLEN] = '\0';
- return 0;
-}
-
-