pkix_pl_ocsprequest.c (13569B)
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_ocsprequest.c 6 * 7 */ 8 9 #include "pkix_pl_ocsprequest.h" 10 11 /* --Private-OcspRequest-Functions------------------------------------- */ 12 13 /* 14 * FUNCTION: pkix_pl_OcspRequest_Destroy 15 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) 16 */ 17 static PKIX_Error * 18 pkix_pl_OcspRequest_Destroy( 19 PKIX_PL_Object *object, 20 void *plContext) 21 { 22 PKIX_PL_OcspRequest *ocspReq = NULL; 23 24 PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Destroy"); 25 PKIX_NULLCHECK_ONE(object); 26 27 PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPREQUEST_TYPE, plContext), 28 PKIX_OBJECTNOTOCSPREQUEST); 29 30 ocspReq = (PKIX_PL_OcspRequest *)object; 31 32 if (ocspReq->decoded != NULL) { 33 CERT_DestroyOCSPRequest(ocspReq->decoded); 34 } 35 36 if (ocspReq->encoded != NULL) { 37 SECITEM_FreeItem(ocspReq->encoded, PR_TRUE); 38 } 39 40 if (ocspReq->location != NULL) { 41 PORT_Free(ocspReq->location); 42 } 43 44 PKIX_DECREF(ocspReq->cert); 45 PKIX_DECREF(ocspReq->validity); 46 PKIX_DECREF(ocspReq->signerCert); 47 48 cleanup: 49 50 PKIX_RETURN(OCSPREQUEST); 51 } 52 53 /* 54 * FUNCTION: pkix_pl_OcspRequest_Hashcode 55 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) 56 */ 57 static PKIX_Error * 58 pkix_pl_OcspRequest_Hashcode( 59 PKIX_PL_Object *object, 60 PKIX_UInt32 *pHashcode, 61 void *plContext) 62 { 63 PKIX_UInt32 certHash = 0; 64 PKIX_UInt32 dateHash = 0; 65 PKIX_UInt32 extensionHash = 0; 66 PKIX_UInt32 signerHash = 0; 67 PKIX_PL_OcspRequest *ocspRq = NULL; 68 69 PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Hashcode"); 70 PKIX_NULLCHECK_TWO(object, pHashcode); 71 72 PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPREQUEST_TYPE, plContext), 73 PKIX_OBJECTNOTOCSPREQUEST); 74 75 ocspRq = (PKIX_PL_OcspRequest *)object; 76 77 *pHashcode = 0; 78 79 PKIX_HASHCODE(ocspRq->cert, &certHash, plContext, 80 PKIX_CERTHASHCODEFAILED); 81 82 PKIX_HASHCODE(ocspRq->validity, &dateHash, plContext, 83 PKIX_DATEHASHCODEFAILED); 84 85 if (ocspRq->addServiceLocator == PKIX_TRUE) { 86 extensionHash = 0xff; 87 } 88 89 PKIX_HASHCODE(ocspRq->signerCert, &signerHash, plContext, 90 PKIX_CERTHASHCODEFAILED); 91 92 *pHashcode = (((((extensionHash << 8) | certHash) << 8) | 93 dateHash) << 8) | signerHash; 94 95 cleanup: 96 97 PKIX_RETURN(OCSPREQUEST); 98 99 } 100 101 /* 102 * FUNCTION: pkix_pl_OcspRequest_Equals 103 * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) 104 */ 105 static PKIX_Error * 106 pkix_pl_OcspRequest_Equals( 107 PKIX_PL_Object *firstObj, 108 PKIX_PL_Object *secondObj, 109 PKIX_Boolean *pResult, 110 void *plContext) 111 { 112 PKIX_Boolean match = PKIX_FALSE; 113 PKIX_UInt32 secondType = 0; 114 PKIX_PL_OcspRequest *firstReq = NULL; 115 PKIX_PL_OcspRequest *secondReq = NULL; 116 117 PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Equals"); 118 PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult); 119 120 /* test that firstObj is a OcspRequest */ 121 PKIX_CHECK(pkix_CheckType(firstObj, PKIX_OCSPREQUEST_TYPE, plContext), 122 PKIX_FIRSTOBJARGUMENTNOTOCSPREQUEST); 123 124 /* 125 * Since we know firstObj is a OcspRequest, if both references are 126 * identical, they must be equal 127 */ 128 if (firstObj == secondObj){ 129 match = PKIX_TRUE; 130 goto cleanup; 131 } 132 133 /* 134 * If secondObj isn't a OcspRequest, we don't throw an error. 135 * We simply return a Boolean result of FALSE 136 */ 137 PKIX_CHECK(PKIX_PL_Object_GetType 138 (secondObj, &secondType, plContext), 139 PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); 140 if (secondType != PKIX_OCSPREQUEST_TYPE) { 141 goto cleanup; 142 } 143 144 firstReq = (PKIX_PL_OcspRequest *)firstObj; 145 secondReq = (PKIX_PL_OcspRequest *)secondObj; 146 147 if (firstReq->addServiceLocator != secondReq->addServiceLocator) { 148 goto cleanup; 149 } 150 151 PKIX_EQUALS(firstReq->cert, secondReq->cert, &match, plContext, 152 PKIX_CERTEQUALSFAILED); 153 154 if (match == PKIX_FALSE) { 155 goto cleanup; 156 } 157 158 PKIX_EQUALS(firstReq->validity, secondReq->validity, &match, plContext, 159 PKIX_DATEEQUALSFAILED); 160 161 if (match == PKIX_FALSE) { 162 goto cleanup; 163 } 164 165 PKIX_EQUALS 166 (firstReq->signerCert, secondReq->signerCert, &match, plContext, 167 PKIX_CERTEQUALSFAILED); 168 169 cleanup: 170 171 *pResult = match; 172 173 PKIX_RETURN(OCSPREQUEST); 174 } 175 176 /* 177 * FUNCTION: pkix_pl_OcspRequest_RegisterSelf 178 * DESCRIPTION: 179 * Registers PKIX_OCSPREQUEST_TYPE and its related functions with 180 * systemClasses[] 181 * PARAMETERS: 182 * "plContext" 183 * Platform-specific context pointer. 184 * THREAD SAFETY: 185 * Not Thread Safe - for performance and complexity reasons 186 * 187 * Since this function is only called by PKIX_PL_Initialize, which should 188 * only be called once, it is acceptable that this function is not 189 * thread-safe. 190 */ 191 PKIX_Error * 192 pkix_pl_OcspRequest_RegisterSelf(void *plContext) 193 { 194 extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; 195 pkix_ClassTable_Entry entry; 196 197 PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_RegisterSelf"); 198 199 entry.description = "OcspRequest"; 200 entry.objCounter = 0; 201 entry.typeObjectSize = sizeof(PKIX_PL_OcspRequest); 202 entry.destructor = pkix_pl_OcspRequest_Destroy; 203 entry.equalsFunction = pkix_pl_OcspRequest_Equals; 204 entry.hashcodeFunction = pkix_pl_OcspRequest_Hashcode; 205 entry.toStringFunction = NULL; 206 entry.comparator = NULL; 207 entry.duplicateFunction = pkix_duplicateImmutable; 208 209 systemClasses[PKIX_OCSPREQUEST_TYPE] = entry; 210 211 PKIX_RETURN(OCSPREQUEST); 212 } 213 214 /* --Public-Functions------------------------------------------------------- */ 215 216 /* 217 * FUNCTION: pkix_pl_OcspRequest_Create 218 * DESCRIPTION: 219 * 220 * This function creates an OcspRequest to be used in validating the Cert 221 * pointed to by "cert" and storing the result at "pRequest". If a URI 222 * is found for an OCSP responder, PKIX_TRUE is stored at "pURIFound". If no 223 * URI is found, PKIX_FALSE is stored. 224 * 225 * If a Date is provided in "validity" it may be used in the search for the 226 * issuer of "cert" but has no effect on the request itself. If 227 * "addServiceLocator" is TRUE, the AddServiceLocator extension will be 228 * included in the Request. If "signerCert" is provided it will be used to sign 229 * the Request. (Note: this signed request feature is not currently supported.) 230 * 231 * PARAMETERS: 232 * "cert" 233 * Address of the Cert for which an OcspRequest is to be created. Must be 234 * non-NULL. 235 * "validity" 236 * Address of the Date for which the Cert's validity is to be determined. 237 * May be NULL. 238 * "signerCert" 239 * Address of the Cert to be used, if present, in signing the request. 240 * May be NULL. 241 * "pRequest" 242 * Address at which the result is stored. Must be non-NULL. 243 * "plContext" 244 * Platform-specific context pointer. 245 * THREAD SAFETY: 246 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 247 * RETURNS: 248 * Returns NULL if the function succeeds. 249 * Returns an OcspRequest Error if the function fails in a non-fatal way. 250 * Returns a Fatal Error if the function fails in an unrecoverable way. 251 */ 252 PKIX_Error * 253 pkix_pl_OcspRequest_Create( 254 PKIX_PL_Cert *cert, 255 PKIX_PL_OcspCertID *cid, 256 PKIX_PL_Date *validity, 257 PKIX_PL_Cert *signerCert, 258 PKIX_UInt32 methodFlags, 259 PKIX_Boolean *pURIFound, 260 PKIX_PL_OcspRequest **pRequest, 261 void *plContext) 262 { 263 PKIX_PL_OcspRequest *ocspRequest = NULL; 264 265 CERTCertDBHandle *handle = NULL; 266 SECStatus rv = SECFailure; 267 SECItem *encoding = NULL; 268 CERTOCSPRequest *certRequest = NULL; 269 PRTime time = 0; 270 PRBool addServiceLocatorExtension = PR_FALSE; 271 CERTCertificate *nssCert = NULL; 272 CERTCertificate *nssSignerCert = NULL; 273 char *location = NULL; 274 PRErrorCode locError = 0; 275 PKIX_Boolean canUseDefaultSource = PKIX_FALSE; 276 277 PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Create"); 278 PKIX_NULLCHECK_TWO(cert, pRequest); 279 280 /* create a PKIX_PL_OcspRequest object */ 281 PKIX_CHECK(PKIX_PL_Object_Alloc 282 (PKIX_OCSPREQUEST_TYPE, 283 sizeof (PKIX_PL_OcspRequest), 284 (PKIX_PL_Object **)&ocspRequest, 285 plContext), 286 PKIX_COULDNOTCREATEOBJECT); 287 288 PKIX_INCREF(cert); 289 ocspRequest->cert = cert; 290 291 PKIX_INCREF(validity); 292 ocspRequest->validity = validity; 293 294 PKIX_INCREF(signerCert); 295 ocspRequest->signerCert = signerCert; 296 297 ocspRequest->decoded = NULL; 298 ocspRequest->encoded = NULL; 299 300 ocspRequest->location = NULL; 301 302 nssCert = cert->nssCert; 303 304 /* 305 * Does this Cert have an Authority Information Access extension with 306 * the URI of an OCSP responder? 307 */ 308 handle = CERT_GetDefaultCertDB(); 309 310 if (!(methodFlags & PKIX_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE)) { 311 canUseDefaultSource = PKIX_TRUE; 312 } 313 location = ocsp_GetResponderLocation(handle, nssCert, 314 canUseDefaultSource, 315 &addServiceLocatorExtension); 316 if (location == NULL) { 317 locError = PORT_GetError(); 318 if (locError == SEC_ERROR_EXTENSION_NOT_FOUND || 319 locError == SEC_ERROR_CERT_BAD_ACCESS_LOCATION) { 320 PORT_SetError(0); 321 *pURIFound = PKIX_FALSE; 322 goto cleanup; 323 } 324 PKIX_ERROR(PKIX_ERRORFINDINGORPROCESSINGURI); 325 } 326 327 ocspRequest->location = location; 328 *pURIFound = PKIX_TRUE; 329 330 if (signerCert != NULL) { 331 nssSignerCert = signerCert->nssCert; 332 } 333 334 if (validity != NULL) { 335 PKIX_CHECK(pkix_pl_Date_GetPRTime(validity, &time, plContext), 336 PKIX_DATEGETPRTIMEFAILED); 337 } else { 338 time = PR_Now(); 339 } 340 341 certRequest = cert_CreateSingleCertOCSPRequest( 342 cid->certID, cert->nssCert, time, 343 addServiceLocatorExtension, nssSignerCert); 344 345 ocspRequest->decoded = certRequest; 346 347 if (certRequest == NULL) { 348 PKIX_ERROR(PKIX_UNABLETOCREATECERTOCSPREQUEST); 349 } 350 351 rv = CERT_AddOCSPAcceptableResponses( 352 certRequest, SEC_OID_PKIX_OCSP_BASIC_RESPONSE); 353 354 if (rv == SECFailure) { 355 PKIX_ERROR(PKIX_UNABLETOADDACCEPTABLERESPONSESTOREQUEST); 356 } 357 358 encoding = CERT_EncodeOCSPRequest(NULL, certRequest, NULL); 359 360 ocspRequest->encoded = encoding; 361 362 *pRequest = ocspRequest; 363 ocspRequest = NULL; 364 365 cleanup: 366 PKIX_DECREF(ocspRequest); 367 368 PKIX_RETURN(OCSPREQUEST); 369 } 370 371 /* 372 * FUNCTION: pkix_pl_OcspRequest_GetEncoded 373 * DESCRIPTION: 374 * 375 * This function obtains the encoded message from the OcspRequest pointed to 376 * by "request", storing the result at "pRequest". 377 * 378 * PARAMETERS 379 * "request" 380 * The address of the OcspRequest whose encoded message is to be 381 * retrieved. Must be non-NULL. 382 * "pRequest" 383 * The address at which is stored the address of the encoded message. Must 384 * be non-NULL. 385 * "plContext" 386 * Platform-specific context pointer. 387 * THREAD SAFETY: 388 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 389 * RETURNS: 390 * Returns NULL if the function succeeds. 391 * Returns a Fatal Error if the function fails in an unrecoverable way. 392 */ 393 PKIX_Error * 394 pkix_pl_OcspRequest_GetEncoded( 395 PKIX_PL_OcspRequest *request, 396 SECItem **pRequest, 397 void *plContext) 398 { 399 PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_GetEncoded"); 400 PKIX_NULLCHECK_TWO(request, pRequest); 401 402 *pRequest = request->encoded; 403 404 PKIX_RETURN(OCSPREQUEST); 405 } 406 407 /* 408 * FUNCTION: pkix_pl_OcspRequest_GetLocation 409 * DESCRIPTION: 410 * 411 * This function obtains the location from the OcspRequest pointed to 412 * by "request", storing the result at "pLocation". 413 * 414 * PARAMETERS 415 * "request" 416 * The address of the OcspRequest whose encoded message is to be 417 * retrieved. Must be non-NULL. 418 * "pLocation" 419 * The address at which is stored the address of the location. Must 420 * be non-NULL. 421 * "plContext" 422 * Platform-specific context pointer. 423 * THREAD SAFETY: 424 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 425 * RETURNS: 426 * Returns NULL if the function succeeds. 427 * Returns a Fatal Error if the function fails in an unrecoverable way. 428 */ 429 PKIX_Error * 430 pkix_pl_OcspRequest_GetLocation( 431 PKIX_PL_OcspRequest *request, 432 char **pLocation, 433 void *plContext) 434 { 435 PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_GetLocation"); 436 PKIX_NULLCHECK_TWO(request, pLocation); 437 438 *pLocation = request->location; 439 440 PKIX_RETURN(OCSPREQUEST); 441 }