pkix_pl_date.c (13629B)
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 * pkix_pl_date.c 6 * 7 * Date Object Definitions 8 * 9 */ 10 11 #include "pkix_pl_date.h" 12 13 /* --Private-Date-Functions------------------------------------- */ 14 /* 15 * FUNCTION: pkix_pl_Date_GetPRTime 16 * DESCRIPTION: 17 * 18 * Translates into a PRTime the Date embodied by the Date object pointed to 19 * by "date", and stores it at "pPRTime". 20 * 21 * PARAMETERS 22 * "date" 23 * Address of Date whose PRTime representation is desired. Must be 24 * non-NULL. 25 * "pPRTime" 26 * Address where PRTime value will be stored. Must be non-NULL. 27 * "plContext" - Platform-specific context pointer. 28 * THREAD SAFETY: 29 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 30 * RETURNS: 31 * Returns NULL if the function succeeds. 32 * Returns a Date Error if the function fails in a non-fatal way. 33 * Returns a Fatal Error if the function fails in an unrecoverable way. 34 */ 35 PKIX_Error * 36 pkix_pl_Date_GetPRTime( 37 PKIX_PL_Date *date, 38 PRTime *pPRTime, 39 void *plContext) 40 { 41 PKIX_ENTER(DATE, "PKIX_PL_Date_GetPRTime"); 42 PKIX_NULLCHECK_TWO(date, pPRTime); 43 44 *pPRTime = date->nssTime; 45 46 PKIX_RETURN(DATE); 47 } 48 49 /* 50 * FUNCTION: pkix_pl_Date_CreateFromPRTime 51 * DESCRIPTION: 52 * 53 * Creates a new Date from the PRTime whose value is "prtime", and stores the 54 * result at "pDate". 55 * 56 * PARAMETERS 57 * "prtime" 58 * The PRTime value to be embodied in the new Date object. 59 * "pDate" 60 * Address where object pointer will be stored. Must be non-NULL. 61 * "plContext" - Platform-specific context pointer. 62 * THREAD SAFETY: 63 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 64 * RETURNS: 65 * Returns NULL if the function succeeds. 66 * Returns a Date Error if the function fails in a non-fatal way. 67 * Returns a Fatal Error if the function fails in an unrecoverable way. 68 */ 69 PKIX_Error * 70 pkix_pl_Date_CreateFromPRTime( 71 PRTime prtime, 72 PKIX_PL_Date **pDate, 73 void *plContext) 74 { 75 PKIX_PL_Date *date = NULL; 76 77 PKIX_ENTER(DATE, "PKIX_PL_Date_CreateFromPRTime"); 78 PKIX_NULLCHECK_ONE(pDate); 79 80 /* create a PKIX_PL_Date object */ 81 PKIX_CHECK(PKIX_PL_Object_Alloc 82 (PKIX_DATE_TYPE, 83 sizeof (PKIX_PL_Date), 84 (PKIX_PL_Object **)&date, 85 plContext), 86 PKIX_COULDNOTCREATEOBJECT); 87 /* populate the nssTime field */ 88 date->nssTime = prtime; 89 *pDate = date; 90 cleanup: 91 PKIX_RETURN(DATE); 92 } 93 94 /* 95 * FUNCTION: pkix_pl_Date_ToString_Helper 96 * DESCRIPTION: 97 * 98 * Helper function that creates a string representation of the SECItem pointed 99 * to by "nssTime" (which represents a date) and stores it at "pString". 100 * 101 * PARAMETERS 102 * "nssTime" 103 * Address of SECItem whose string representation is desired. 104 * Must be non-NULL. 105 * "pString" 106 * Address where object pointer will be stored. Must be non-NULL. 107 * "plContext" - Platform-specific context pointer. 108 * THREAD SAFETY: 109 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 110 * RETURNS: 111 * Returns NULL if the function succeeds. 112 * Returns a Date Error if the function fails in a non-fatal way. 113 * Returns a Fatal Error if the function fails in an unrecoverable way. 114 */ 115 PKIX_Error * 116 pkix_pl_Date_ToString_Helper( 117 SECItem *nssTime, 118 PKIX_PL_String **pString, 119 void *plContext) 120 { 121 char *asciiDate = NULL; 122 123 PKIX_ENTER(DATE, "pkix_pl_Date_ToString_Helper"); 124 PKIX_NULLCHECK_TWO(nssTime, pString); 125 126 switch (nssTime->type) { 127 case siUTCTime: 128 PKIX_PL_NSSCALLRV 129 (DATE, asciiDate, DER_UTCDayToAscii, (nssTime)); 130 if (!asciiDate){ 131 PKIX_ERROR(PKIX_DERUTCTIMETOASCIIFAILED); 132 } 133 break; 134 case siGeneralizedTime: 135 /* 136 * we don't currently have any way to create GeneralizedTime. 137 * this code is only here so that it will be in place when 138 * we do have the capability to create GeneralizedTime. 139 */ 140 PKIX_PL_NSSCALLRV 141 (DATE, asciiDate, DER_GeneralizedDayToAscii, (nssTime)); 142 if (!asciiDate){ 143 PKIX_ERROR(PKIX_DERGENERALIZEDDAYTOASCIIFAILED); 144 } 145 break; 146 default: 147 PKIX_ERROR(PKIX_UNRECOGNIZEDTIMETYPE); 148 } 149 150 PKIX_CHECK(PKIX_PL_String_Create 151 (PKIX_ESCASCII, asciiDate, 0, pString, plContext), 152 PKIX_STRINGCREATEFAILED); 153 154 cleanup: 155 PR_Free(asciiDate); 156 157 PKIX_RETURN(DATE); 158 } 159 160 161 /* 162 * FUNCTION: pkix_pl_Date_Destroy 163 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) 164 */ 165 static PKIX_Error * 166 pkix_pl_Date_Destroy( 167 PKIX_PL_Object *object, 168 void *plContext) 169 { 170 PKIX_ENTER(DATE, "pkix_pl_Date_Destroy"); 171 PKIX_NULLCHECK_ONE(object); 172 173 PKIX_CHECK(pkix_CheckType(object, PKIX_DATE_TYPE, plContext), 174 PKIX_OBJECTNOTDATE); 175 cleanup: 176 PKIX_RETURN(DATE); 177 } 178 179 /* 180 * FUNCTION: pkix_pl_Date_ToString 181 * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) 182 */ 183 static PKIX_Error * 184 pkix_pl_Date_ToString( 185 PKIX_PL_Object *object, 186 PKIX_PL_String **pString, 187 void *plContext) 188 { 189 PKIX_PL_Date *date = NULL; 190 SECItem nssTime = {siBuffer, NULL, 0}; 191 SECStatus rv; 192 193 PKIX_ENTER(DATE, "pkix_pl_Date_toString"); 194 PKIX_NULLCHECK_TWO(object, pString); 195 196 PKIX_CHECK(pkix_CheckType(object, PKIX_DATE_TYPE, plContext), 197 PKIX_OBJECTNOTDATE); 198 199 date = (PKIX_PL_Date *)object; 200 rv = DER_EncodeTimeChoice(NULL, &nssTime, date->nssTime); 201 if (rv == SECFailure) { 202 PKIX_ERROR(PKIX_DERENCODETIMECHOICEFAILED); 203 } 204 PKIX_CHECK(pkix_pl_Date_ToString_Helper 205 (&nssTime, pString, plContext), 206 PKIX_DATETOSTRINGHELPERFAILED); 207 cleanup: 208 if (nssTime.data) { 209 SECITEM_FreeItem(&nssTime, PR_FALSE); 210 } 211 212 PKIX_RETURN(DATE); 213 } 214 215 /* 216 * FUNCTION: pkix_pl_Date_Hashcode 217 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) 218 */ 219 static PKIX_Error * 220 pkix_pl_Date_Hashcode( 221 PKIX_PL_Object *object, 222 PKIX_UInt32 *pHashcode, 223 void *plContext) 224 { 225 PKIX_PL_Date *date = NULL; 226 PKIX_UInt32 dateHash; 227 228 PKIX_ENTER(DATE, "pkix_pl_Date_Hashcode"); 229 PKIX_NULLCHECK_TWO(object, pHashcode); 230 231 PKIX_CHECK(pkix_CheckType(object, PKIX_DATE_TYPE, plContext), 232 PKIX_OBJECTNOTDATE); 233 234 date = (PKIX_PL_Date *)object; 235 236 PKIX_CHECK(pkix_hash 237 ((const unsigned char *)&date->nssTime, 238 sizeof(date->nssTime), 239 &dateHash, 240 plContext), 241 PKIX_HASHFAILED); 242 243 *pHashcode = dateHash; 244 245 cleanup: 246 247 PKIX_RETURN(DATE); 248 249 } 250 251 /* 252 * FUNCTION: pkix_pl_Date_Comparator 253 * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h) 254 */ 255 static PKIX_Error * 256 pkix_pl_Date_Comparator( 257 PKIX_PL_Object *firstObject, 258 PKIX_PL_Object *secondObject, 259 PKIX_Int32 *pResult, 260 void *plContext) 261 { 262 PRTime firstTime; 263 PRTime secondTime; 264 SECComparison cmpResult; 265 266 PKIX_ENTER(DATE, "pkix_pl_Date_Comparator"); 267 PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); 268 269 PKIX_CHECK(pkix_CheckTypes 270 (firstObject, secondObject, PKIX_DATE_TYPE, plContext), 271 PKIX_ARGUMENTSNOTDATES); 272 273 firstTime = ((PKIX_PL_Date *)firstObject)->nssTime; 274 secondTime = ((PKIX_PL_Date *)secondObject)->nssTime; 275 276 if (firstTime == secondTime) 277 cmpResult = SECEqual; 278 else if (firstTime < secondTime) 279 cmpResult = SECLessThan; 280 else 281 cmpResult = SECGreaterThan; 282 283 *pResult = cmpResult; 284 285 cleanup: 286 287 PKIX_RETURN(DATE); 288 } 289 290 /* 291 * FUNCTION: pkix_pl_Date_Equals 292 * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) 293 */ 294 static PKIX_Error * 295 pkix_pl_Date_Equals( 296 PKIX_PL_Object *firstObject, 297 PKIX_PL_Object *secondObject, 298 PKIX_Boolean *pResult, 299 void *plContext) 300 { 301 PKIX_ENTER(DATE, "pkix_pl_Date_Equals"); 302 PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); 303 304 /* test that firstObject is a Date */ 305 PKIX_CHECK(pkix_CheckType(firstObject, PKIX_DATE_TYPE, plContext), 306 PKIX_FIRSTOBJECTNOTDATE); 307 308 /* 309 * Since we know firstObject is a Date, if both references are 310 * identical, they must be equal 311 */ 312 if (firstObject == secondObject){ 313 *pResult = PKIX_TRUE; 314 goto cleanup; 315 } 316 317 *pResult = PKIX_FALSE; 318 pkixErrorResult = 319 pkix_pl_Date_Comparator(firstObject, secondObject, 320 pResult, plContext); 321 if (pkixErrorResult) { 322 PKIX_DECREF(pkixErrorResult); 323 } 324 325 cleanup: 326 327 PKIX_RETURN(DATE); 328 } 329 330 /* 331 * FUNCTION: pkix_pl_Date_RegisterSelf 332 * DESCRIPTION: 333 * Registers PKIX_DATE_TYPE and its related functions with systemClasses[] 334 * THREAD SAFETY: 335 * Not Thread Safe - for performance and complexity reasons 336 * 337 * Since this function is only called by PKIX_PL_Initialize, which should 338 * only be called once, it is acceptable that this function is not 339 * thread-safe. 340 */ 341 PKIX_Error * 342 pkix_pl_Date_RegisterSelf(void *plContext) 343 { 344 extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; 345 pkix_ClassTable_Entry* entry = &systemClasses[PKIX_DATE_TYPE]; 346 347 PKIX_ENTER(CRLCHECKER, "pkix_CrlDp_RegisterSelf"); 348 349 entry->description = "Date"; 350 entry->typeObjectSize = sizeof(PKIX_PL_Date); 351 entry->destructor = pkix_pl_Date_Destroy; 352 entry->equalsFunction = pkix_pl_Date_Equals; 353 entry->hashcodeFunction = pkix_pl_Date_Hashcode; 354 entry->toStringFunction = pkix_pl_Date_ToString; 355 entry->comparator = pkix_pl_Date_Comparator; 356 entry->duplicateFunction = pkix_duplicateImmutable; 357 358 PKIX_RETURN(DATE); 359 } 360 361 /* --Public-Functions------------------------------------------------------- */ 362 363 /* 364 * FUNCTION: PKIX_PL_Date_Create_UTCTime (see comments in pkix_pl_pki.h) 365 */ 366 PKIX_Error * 367 PKIX_PL_Date_Create_UTCTime( 368 PKIX_PL_String *stringRep, 369 PKIX_PL_Date **pDate, 370 void *plContext) 371 { 372 PKIX_PL_Date *date = NULL; 373 char *asciiString = NULL; 374 PKIX_UInt32 escAsciiLength; 375 SECStatus rv; 376 PRTime time; 377 378 PKIX_ENTER(DATE, "PKIX_PL_Date_Create_UTCTime"); 379 PKIX_NULLCHECK_ONE(pDate); 380 381 if (stringRep == NULL){ 382 PKIX_DATE_DEBUG("\t\tCalling PR_Now).\n"); 383 time = PR_Now(); 384 } else { 385 /* convert the input PKIX_PL_String to PKIX_ESCASCII */ 386 PKIX_CHECK(PKIX_PL_String_GetEncoded 387 (stringRep, 388 PKIX_ESCASCII, 389 (void **)&asciiString, 390 &escAsciiLength, 391 plContext), 392 PKIX_STRINGGETENCODEDFAILED); 393 394 PKIX_DATE_DEBUG("\t\tCalling DER_AsciiToTime).\n"); 395 /* DER_AsciiToTime only supports UTCTime (2-digit years) */ 396 rv = DER_AsciiToTime(&time, asciiString); 397 if (rv != SECSuccess){ 398 PKIX_ERROR(PKIX_DERASCIITOTIMEFAILED); 399 } 400 } 401 402 /* create a PKIX_PL_Date object */ 403 PKIX_CHECK(PKIX_PL_Object_Alloc 404 (PKIX_DATE_TYPE, 405 sizeof (PKIX_PL_Date), 406 (PKIX_PL_Object **)&date, 407 plContext), 408 PKIX_COULDNOTCREATEOBJECT); 409 410 /* populate the nssTime field */ 411 date->nssTime = time; 412 *pDate = date; 413 414 cleanup: 415 PKIX_FREE(asciiString); 416 417 PKIX_RETURN(DATE); 418 } 419 420 /* 421 * FUNCTION: PKIX_PL_Date_Create_CurrentOffBySeconds 422 * (see comments in pkix_pl_pki.h) 423 */ 424 PKIX_Error * 425 PKIX_PL_Date_Create_CurrentOffBySeconds( 426 PKIX_Int32 secondsOffset, 427 PKIX_PL_Date **pDate, 428 void *plContext) 429 { 430 PKIX_PL_Date *date = NULL; 431 PRTime time; 432 433 PKIX_ENTER(DATE, "PKIX_PL_Date_Create_CurrentOffBySeconds"); 434 PKIX_NULLCHECK_ONE(pDate); 435 436 time = PR_Now() + PR_SecondsToInterval(secondsOffset); 437 /* create a PKIX_PL_Date object */ 438 PKIX_CHECK(PKIX_PL_Object_Alloc 439 (PKIX_DATE_TYPE, 440 sizeof (PKIX_PL_Date), 441 (PKIX_PL_Object **)&date, 442 plContext), 443 PKIX_COULDNOTCREATEOBJECT); 444 445 /* populate the nssTime field */ 446 date->nssTime = time; 447 *pDate = date; 448 449 cleanup: 450 PKIX_RETURN(DATE); 451 } 452 453 PKIX_Error * 454 PKIX_PL_Date_CreateFromPRTime( 455 PRTime prtime, 456 PKIX_PL_Date **pDate, 457 void *plContext) 458 { 459 PKIX_ENTER(DATE, "PKIX_PL_Date_CreateFromPRTime"); 460 PKIX_CHECK( 461 pkix_pl_Date_CreateFromPRTime(prtime, pDate, plContext), 462 PKIX_DATECREATEFROMPRTIMEFAILED); 463 464 cleanup: 465 PKIX_RETURN(DATE); 466 }