andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: /* andre@0: * pkix_pl_date.c andre@0: * andre@0: * Date Object Definitions andre@0: * andre@0: */ andre@0: andre@0: #include "pkix_pl_date.h" andre@0: andre@0: /* --Private-Date-Functions------------------------------------- */ andre@0: /* andre@0: * FUNCTION: pkix_pl_Date_GetPRTime andre@0: * DESCRIPTION: andre@0: * andre@0: * Translates into a PRTime the Date embodied by the Date object pointed to andre@0: * by "date", and stores it at "pPRTime". andre@0: * andre@0: * PARAMETERS andre@0: * "date" andre@0: * Address of Date whose PRTime representation is desired. Must be andre@0: * non-NULL. andre@0: * "pPRTime" andre@0: * Address where PRTime value will be stored. Must be non-NULL. andre@0: * "plContext" - Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns a Date Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_Date_GetPRTime( andre@0: PKIX_PL_Date *date, andre@0: PRTime *pPRTime, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(DATE, "PKIX_PL_Date_GetPRTime"); andre@0: PKIX_NULLCHECK_TWO(date, pPRTime); andre@0: andre@0: *pPRTime = date->nssTime; andre@0: andre@0: PKIX_RETURN(DATE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_Date_CreateFromPRTime andre@0: * DESCRIPTION: andre@0: * andre@0: * Creates a new Date from the PRTime whose value is "prtime", and stores the andre@0: * result at "pDate". andre@0: * andre@0: * PARAMETERS andre@0: * "prtime" andre@0: * The PRTime value to be embodied in the new Date object. andre@0: * "pDate" andre@0: * Address where object pointer will be stored. Must be non-NULL. andre@0: * "plContext" - Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns a Date Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_Date_CreateFromPRTime( andre@0: PRTime prtime, andre@0: PKIX_PL_Date **pDate, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_Date *date = NULL; andre@0: andre@0: PKIX_ENTER(DATE, "PKIX_PL_Date_CreateFromPRTime"); andre@0: PKIX_NULLCHECK_ONE(pDate); andre@0: andre@0: /* create a PKIX_PL_Date object */ andre@0: PKIX_CHECK(PKIX_PL_Object_Alloc andre@0: (PKIX_DATE_TYPE, andre@0: sizeof (PKIX_PL_Date), andre@0: (PKIX_PL_Object **)&date, andre@0: plContext), andre@0: PKIX_COULDNOTCREATEOBJECT); andre@0: /* populate the nssTime field */ andre@0: date->nssTime = prtime; andre@0: *pDate = date; andre@0: cleanup: andre@0: PKIX_RETURN(DATE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_Date_ToString_Helper andre@0: * DESCRIPTION: andre@0: * andre@0: * Helper function that creates a string representation of the SECItem pointed andre@0: * to by "nssTime" (which represents a date) and stores it at "pString". andre@0: * andre@0: * PARAMETERS andre@0: * "nssTime" andre@0: * Address of SECItem whose string representation is desired. andre@0: * Must be non-NULL. andre@0: * "pString" andre@0: * Address where object pointer will be stored. Must be non-NULL. andre@0: * "plContext" - Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns a Date Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_Date_ToString_Helper( andre@0: SECItem *nssTime, andre@0: PKIX_PL_String **pString, andre@0: void *plContext) andre@0: { andre@0: char *asciiDate = NULL; andre@0: andre@0: PKIX_ENTER(DATE, "pkix_pl_Date_ToString_Helper"); andre@0: PKIX_NULLCHECK_TWO(nssTime, pString); andre@0: andre@0: switch (nssTime->type) { andre@0: case siUTCTime: andre@0: PKIX_PL_NSSCALLRV andre@0: (DATE, asciiDate, DER_UTCDayToAscii, (nssTime)); andre@0: if (!asciiDate){ andre@0: PKIX_ERROR(PKIX_DERUTCTIMETOASCIIFAILED); andre@0: } andre@0: break; andre@0: case siGeneralizedTime: andre@0: /* andre@0: * we don't currently have any way to create GeneralizedTime. andre@0: * this code is only here so that it will be in place when andre@0: * we do have the capability to create GeneralizedTime. andre@0: */ andre@0: PKIX_PL_NSSCALLRV andre@0: (DATE, asciiDate, DER_GeneralizedDayToAscii, (nssTime)); andre@0: if (!asciiDate){ andre@0: PKIX_ERROR(PKIX_DERGENERALIZEDDAYTOASCIIFAILED); andre@0: } andre@0: break; andre@0: default: andre@0: PKIX_ERROR(PKIX_UNRECOGNIZEDTIMETYPE); andre@0: } andre@0: andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, asciiDate, 0, pString, plContext), andre@0: PKIX_STRINGCREATEFAILED); andre@0: andre@0: cleanup: andre@0: PR_Free(asciiDate); andre@0: andre@0: PKIX_RETURN(DATE); andre@0: } andre@0: andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_Date_Destroy andre@0: * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_Date_Destroy( andre@0: PKIX_PL_Object *object, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(DATE, "pkix_pl_Date_Destroy"); andre@0: PKIX_NULLCHECK_ONE(object); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_DATE_TYPE, plContext), andre@0: PKIX_OBJECTNOTDATE); andre@0: cleanup: andre@0: PKIX_RETURN(DATE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_Date_ToString andre@0: * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_Date_ToString( andre@0: PKIX_PL_Object *object, andre@0: PKIX_PL_String **pString, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_Date *date = NULL; andre@0: SECItem nssTime = {siBuffer, NULL, 0}; andre@0: SECStatus rv; andre@0: andre@0: PKIX_ENTER(DATE, "pkix_pl_Date_toString"); andre@0: PKIX_NULLCHECK_TWO(object, pString); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_DATE_TYPE, plContext), andre@0: PKIX_OBJECTNOTDATE); andre@0: andre@0: date = (PKIX_PL_Date *)object; andre@0: rv = DER_EncodeTimeChoice(NULL, &nssTime, date->nssTime); andre@0: if (rv == SECFailure) { andre@0: PKIX_ERROR(PKIX_DERENCODETIMECHOICEFAILED); andre@0: } andre@0: PKIX_CHECK(pkix_pl_Date_ToString_Helper andre@0: (&nssTime, pString, plContext), andre@0: PKIX_DATETOSTRINGHELPERFAILED); andre@0: cleanup: andre@0: if (nssTime.data) { andre@0: SECITEM_FreeItem(&nssTime, PR_FALSE); andre@0: } andre@0: andre@0: PKIX_RETURN(DATE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_Date_Hashcode andre@0: * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_Date_Hashcode( andre@0: PKIX_PL_Object *object, andre@0: PKIX_UInt32 *pHashcode, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_Date *date = NULL; andre@0: PKIX_UInt32 dateHash; andre@0: andre@0: PKIX_ENTER(DATE, "pkix_pl_Date_Hashcode"); andre@0: PKIX_NULLCHECK_TWO(object, pHashcode); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_DATE_TYPE, plContext), andre@0: PKIX_OBJECTNOTDATE); andre@0: andre@0: date = (PKIX_PL_Date *)object; andre@0: andre@0: PKIX_CHECK(pkix_hash andre@0: ((const unsigned char *)&date->nssTime, andre@0: sizeof(date->nssTime), andre@0: &dateHash, andre@0: plContext), andre@0: PKIX_HASHFAILED); andre@0: andre@0: *pHashcode = dateHash; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(DATE); andre@0: andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_Date_Comparator andre@0: * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_Date_Comparator( andre@0: PKIX_PL_Object *firstObject, andre@0: PKIX_PL_Object *secondObject, andre@0: PKIX_Int32 *pResult, andre@0: void *plContext) andre@0: { andre@0: PRTime firstTime; andre@0: PRTime secondTime; andre@0: SECComparison cmpResult; andre@0: andre@0: PKIX_ENTER(DATE, "pkix_pl_Date_Comparator"); andre@0: PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); andre@0: andre@0: PKIX_CHECK(pkix_CheckTypes andre@0: (firstObject, secondObject, PKIX_DATE_TYPE, plContext), andre@0: PKIX_ARGUMENTSNOTDATES); andre@0: andre@0: firstTime = ((PKIX_PL_Date *)firstObject)->nssTime; andre@0: secondTime = ((PKIX_PL_Date *)secondObject)->nssTime; andre@0: andre@0: if (firstTime == secondTime) andre@0: cmpResult = SECEqual; andre@0: else if (firstTime < secondTime) andre@0: cmpResult = SECLessThan; andre@0: else andre@0: cmpResult = SECGreaterThan; andre@0: andre@0: *pResult = cmpResult; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(DATE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_Date_Equals andre@0: * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_Date_Equals( andre@0: PKIX_PL_Object *firstObject, andre@0: PKIX_PL_Object *secondObject, andre@0: PKIX_Boolean *pResult, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(DATE, "pkix_pl_Date_Equals"); andre@0: PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); andre@0: andre@0: /* test that firstObject is a Date */ andre@0: PKIX_CHECK(pkix_CheckType(firstObject, PKIX_DATE_TYPE, plContext), andre@0: PKIX_FIRSTOBJECTNOTDATE); andre@0: andre@0: /* andre@0: * Since we know firstObject is a Date, if both references are andre@0: * identical, they must be equal andre@0: */ andre@0: if (firstObject == secondObject){ andre@0: *pResult = PKIX_TRUE; andre@0: goto cleanup; andre@0: } andre@0: andre@0: *pResult = PKIX_FALSE; andre@0: pkixErrorResult = andre@0: pkix_pl_Date_Comparator(firstObject, secondObject, andre@0: pResult, plContext); andre@0: if (pkixErrorResult) { andre@0: PKIX_DECREF(pkixErrorResult); andre@0: } andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(DATE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_Date_RegisterSelf andre@0: * DESCRIPTION: andre@0: * Registers PKIX_DATE_TYPE and its related functions with systemClasses[] andre@0: * THREAD SAFETY: andre@0: * Not Thread Safe - for performance and complexity reasons andre@0: * andre@0: * Since this function is only called by PKIX_PL_Initialize, which should andre@0: * only be called once, it is acceptable that this function is not andre@0: * thread-safe. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_Date_RegisterSelf(void *plContext) andre@0: { andre@0: extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; andre@0: pkix_ClassTable_Entry* entry = &systemClasses[PKIX_DATE_TYPE]; andre@0: andre@0: PKIX_ENTER(CRLCHECKER, "pkix_CrlDp_RegisterSelf"); andre@0: andre@0: entry->description = "Date"; andre@0: entry->typeObjectSize = sizeof(PKIX_PL_Date); andre@0: entry->destructor = pkix_pl_Date_Destroy; andre@0: entry->equalsFunction = pkix_pl_Date_Equals; andre@0: entry->hashcodeFunction = pkix_pl_Date_Hashcode; andre@0: entry->toStringFunction = pkix_pl_Date_ToString; andre@0: entry->comparator = pkix_pl_Date_Comparator; andre@0: entry->duplicateFunction = pkix_duplicateImmutable; andre@0: andre@0: PKIX_RETURN(DATE); andre@0: } andre@0: andre@0: /* --Public-Functions------------------------------------------------------- */ andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_PL_Date_Create_UTCTime (see comments in pkix_pl_pki.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_PL_Date_Create_UTCTime( andre@0: PKIX_PL_String *stringRep, andre@0: PKIX_PL_Date **pDate, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_Date *date = NULL; andre@0: char *asciiString = NULL; andre@0: PKIX_UInt32 escAsciiLength; andre@0: SECStatus rv; andre@0: PRTime time; andre@0: andre@0: PKIX_ENTER(DATE, "PKIX_PL_Date_Create_UTCTime"); andre@0: PKIX_NULLCHECK_ONE(pDate); andre@0: andre@0: if (stringRep == NULL){ andre@0: PKIX_DATE_DEBUG("\t\tCalling PR_Now).\n"); andre@0: time = PR_Now(); andre@0: } else { andre@0: /* convert the input PKIX_PL_String to PKIX_ESCASCII */ andre@0: PKIX_CHECK(PKIX_PL_String_GetEncoded andre@0: (stringRep, andre@0: PKIX_ESCASCII, andre@0: (void **)&asciiString, andre@0: &escAsciiLength, andre@0: plContext), andre@0: PKIX_STRINGGETENCODEDFAILED); andre@0: andre@0: PKIX_DATE_DEBUG("\t\tCalling DER_AsciiToTime).\n"); andre@0: /* DER_AsciiToTime only supports UTCTime (2-digit years) */ andre@0: rv = DER_AsciiToTime(&time, asciiString); andre@0: if (rv != SECSuccess){ andre@0: PKIX_ERROR(PKIX_DERASCIITOTIMEFAILED); andre@0: } andre@0: } andre@0: andre@0: /* create a PKIX_PL_Date object */ andre@0: PKIX_CHECK(PKIX_PL_Object_Alloc andre@0: (PKIX_DATE_TYPE, andre@0: sizeof (PKIX_PL_Date), andre@0: (PKIX_PL_Object **)&date, andre@0: plContext), andre@0: PKIX_COULDNOTCREATEOBJECT); andre@0: andre@0: /* populate the nssTime field */ andre@0: date->nssTime = time; andre@0: *pDate = date; andre@0: andre@0: cleanup: andre@0: PKIX_FREE(asciiString); andre@0: andre@0: PKIX_RETURN(DATE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_PL_Date_Create_CurrentOffBySeconds andre@0: * (see comments in pkix_pl_pki.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_PL_Date_Create_CurrentOffBySeconds( andre@0: PKIX_Int32 secondsOffset, andre@0: PKIX_PL_Date **pDate, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_Date *date = NULL; andre@0: PRTime time; andre@0: andre@0: PKIX_ENTER(DATE, "PKIX_PL_Date_Create_CurrentOffBySeconds"); andre@0: PKIX_NULLCHECK_ONE(pDate); andre@0: andre@0: time = PR_Now() + PR_SecondsToInterval(secondsOffset); andre@0: /* create a PKIX_PL_Date object */ andre@0: PKIX_CHECK(PKIX_PL_Object_Alloc andre@0: (PKIX_DATE_TYPE, andre@0: sizeof (PKIX_PL_Date), andre@0: (PKIX_PL_Object **)&date, andre@0: plContext), andre@0: PKIX_COULDNOTCREATEOBJECT); andre@0: andre@0: /* populate the nssTime field */ andre@0: date->nssTime = time; andre@0: *pDate = date; andre@0: andre@0: cleanup: andre@0: PKIX_RETURN(DATE); andre@0: } andre@0: andre@0: PKIX_Error * andre@0: PKIX_PL_Date_CreateFromPRTime( andre@0: PRTime prtime, andre@0: PKIX_PL_Date **pDate, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(DATE, "PKIX_PL_Date_CreateFromPRTime"); andre@0: PKIX_CHECK( andre@0: pkix_pl_Date_CreateFromPRTime(prtime, pDate, plContext), andre@0: PKIX_DATECREATEFROMPRTIMEFAILED); andre@0: andre@0: cleanup: andre@0: PKIX_RETURN(DATE); andre@0: }