/* * FUNCTION: certCallback * DESCRIPTION: * * This function processes the null-terminated array of SECItems produced by * extracting the contents of a signedData message received in response to an * HTTP cert query. Its address is supplied as a callback function to * CERT_DecodeCertPackage; it is not expected to be called directly. * * Note that it does not conform to the libpkix API standard of returning * a PKIX_Error*. It returns a SECStatus. * * PARAMETERS: * "arg" * The address of the callbackContext provided as a void* argument to * CERT_DecodeCertPackage. Must be non-NULL. * "secitemCerts" * The address of the null-terminated array of SECItems. Must be non-NULL. * "numcerts" * The number of SECItems found in the signedData. Must be non-NULL. * "plContext" * Platform-specific context pointer. * THREAD SAFETY: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) * RETURNS: * Returns SECSuccess if the function succeeds. * Returns SECFailure if the function fails. */ static SECStatus certCallback(void *arg, SECItem **secitemCerts, int numcerts) { callbackContext *cbContext; PKIX_List *pkixCertList = NULL; PKIX_Error *error = NULL; void *plContext = NULL; int itemNum = 0; if ((arg == NULL) || (secitemCerts == NULL)) { return (SECFailure); } cbContext = (callbackContext *)arg; plContext = cbContext->plContext; pkixCertList = cbContext->pkixCertList; for (; itemNum < numcerts; itemNum++ ) { error = pkix_pl_Cert_CreateToList(secitemCerts[itemNum], pkixCertList, plContext); if (error != NULL) { if (error->errClass == PKIX_FATAL_ERROR) { cbContext->error = error; return SECFailure; } /* reuse "error" since we could not destruct the old * * value */ error = PKIX_PL_Object_DecRef((PKIX_PL_Object *)error, plContext); if (error) { /* Treat decref failure as a fatal error. * In this case will leak error, but can not do * anything about it. */ error->errClass = PKIX_FATAL_ERROR; cbContext->error = error; return SECFailure; } } } return SECSuccess; }
static PKIX_Error * toStringCallback( PKIX_PL_Object *obj, PKIX_PL_String **pString, /* ARGSUSED */ void *plContext) { PKIX_Error *errorResult; PKIX_UInt32 type; char *format = "(addr: %x, type: %d)"; PKIX_PL_String *formatString = NULL; errorResult = PKIX_PL_String_Create( PKIX_ESCASCII, format, PL_strlen(format), &formatString, plContext); if (errorResult) testError("PKIX_PL_String_Create failed"); if (pString == plContext) testError("Null String"); type = (unsigned int)0; (void)PKIX_PL_Object_GetType(obj, &type, plContext); errorResult = PKIX_PL_Sprintf(pString, plContext, formatString, (int)obj, type); if (errorResult) testError("PKIX_PL_Sprintf failed"); errorResult = PKIX_PL_Object_DecRef((PKIX_PL_Object *)formatString, plContext); if (errorResult) testError("PKIX_PL_Object_DecRef failed"); return (NULL); }
/* * FUNCTION: PKIX_RevocationChecker_Check */ PKIX_Error * PKIX_RevocationChecker_Check( PKIX_PL_Cert *cert, PKIX_PL_Cert *issuer, PKIX_RevocationChecker *revChecker, PKIX_ProcessingParams *procParams, PKIX_Boolean chainVerificationState, PKIX_Boolean testingLeafCert, PKIX_RevocationStatus *pRevStatus, PKIX_UInt32 *pReasonCode, void **pNbioContext, void *plContext) { PKIX_RevocationStatus overallStatus = PKIX_RevStatus_NoInfo; PKIX_RevocationStatus methodStatus[PKIX_RevocationMethod_MAX]; PKIX_Boolean onlyUseRemoteMethods = PKIX_FALSE; PKIX_UInt32 revFlags = 0; PKIX_List *revList = NULL; PKIX_PL_Date *date = NULL; pkix_RevocationMethod *method = NULL; void *nbioContext; int tries; PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_Check"); PKIX_NULLCHECK_TWO(revChecker, procParams); nbioContext = *pNbioContext; *pNbioContext = NULL; if (testingLeafCert) { revList = revChecker->leafMethodList; revFlags = revChecker->leafMethodListFlags; } else { revList = revChecker->chainMethodList; revFlags = revChecker->chainMethodListFlags; } if (!revList) { /* Return NoInfo status */ goto cleanup; } PORT_Memset(methodStatus, PKIX_RevStatus_NoInfo, sizeof(PKIX_RevocationStatus) * PKIX_RevocationMethod_MAX); date = procParams->date; /* Need to have two loops if we testing all local info first: * first we are going to test all local(cached) info * second, all remote info(fetching) */ for (tries = 0;tries < 2;tries++) { int methodNum = 0; for (;methodNum < revList->length;methodNum++) { PKIX_UInt32 methodFlags = 0; PKIX_DECREF(method); PKIX_CHECK( PKIX_List_GetItem(revList, methodNum, (PKIX_PL_Object**)&method, plContext), PKIX_LISTGETITEMFAILED); methodFlags = method->flags; if (!(methodFlags & PKIX_REV_M_TEST_USING_THIS_METHOD)) { /* Will not check with this method. Skipping... */ continue; } if (!onlyUseRemoteMethods && methodStatus[methodNum] == PKIX_RevStatus_NoInfo) { PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; PKIX_CHECK_NO_GOTO( (*method->localRevChecker)(cert, issuer, date, method, procParams, methodFlags, chainVerificationState, &revStatus, pReasonCode, plContext), PKIX_REVCHECKERCHECKFAILED); methodStatus[methodNum] = revStatus; if (revStatus == PKIX_RevStatus_Revoked) { /* if error was generated use it as final error. */ overallStatus = PKIX_RevStatus_Revoked; goto cleanup; } if (pkixErrorResult) { /* Disregard errors. Only returned revStatus matters. */ PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult, plContext); pkixErrorResult = NULL; } } if ((!(revFlags & PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST) || onlyUseRemoteMethods) && chainVerificationState && methodStatus[methodNum] == PKIX_RevStatus_NoInfo) { if (!(methodFlags & PKIX_REV_M_FORBID_NETWORK_FETCHING)) { PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; PKIX_CHECK_NO_GOTO( (*method->externalRevChecker)(cert, issuer, date, method, procParams, methodFlags, &revStatus, pReasonCode, &nbioContext, plContext), PKIX_REVCHECKERCHECKFAILED); methodStatus[methodNum] = revStatus; if (revStatus == PKIX_RevStatus_Revoked) { /* if error was generated use it as final error. */ overallStatus = PKIX_RevStatus_Revoked; goto cleanup; } if (pkixErrorResult) { /* Disregard errors. Only returned revStatus matters. */ PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult, plContext); pkixErrorResult = NULL; } } else if (methodFlags & PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO) { /* Info is not in the local cache. Network fetching is not * allowed. If need to fail on missing fresh info for the * the method, then we should fail right here.*/ overallStatus = PKIX_RevStatus_Revoked; goto cleanup; } } /* If success and we should not check the next method, then * return a success. */ if (methodStatus[methodNum] == PKIX_RevStatus_Success && !(methodFlags & PKIX_REV_M_CONTINUE_TESTING_ON_FRESH_INFO)) { overallStatus = PKIX_RevStatus_Success; goto cleanup; } } /* inner loop */ if (!onlyUseRemoteMethods && revFlags & PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST && chainVerificationState) { onlyUseRemoteMethods = PKIX_TRUE; continue; } break; } /* outer loop */ if (overallStatus == PKIX_RevStatus_NoInfo && chainVerificationState) { /* The following check makes sence only for chain * validation step, sinse we do not fetch info while * in the process of finding trusted anchor. * For chain building step it is enough to know, that * the cert was not directly revoked by any of the * methods. */ /* Still have no info. But one of the method could * have returned success status(possible if CONTINUE * TESTING ON FRESH INFO flag was used). * If any of the methods have returned Success status, * the overallStatus should be success. */ int methodNum = 0; for (;methodNum < PKIX_RevocationMethod_MAX;methodNum++) { if (methodStatus[methodNum] == PKIX_RevStatus_Success) { overallStatus = PKIX_RevStatus_Success; goto cleanup; } } if (revFlags & PKIX_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE) { overallStatus = PKIX_RevStatus_Revoked; } } cleanup: *pRevStatus = overallStatus; PKIX_DECREF(method); PKIX_RETURN(REVOCATIONCHECKER); }
int test_validatechain_NB(int argc, char *argv[]){ PKIX_ValidateParams *valParams = NULL; PKIX_ValidateResult *valResult = NULL; PKIX_UInt32 actualMinorVersion; PKIX_UInt32 j = 0; PKIX_UInt32 k = 0; PKIX_UInt32 chainLength = 0; PKIX_Boolean testValid = PKIX_TRUE; PKIX_List *chainCerts = NULL; PKIX_PL_Cert *dirCert = NULL; char *dirCertName = NULL; char *anchorCertName = NULL; char *dirName = NULL; PKIX_UInt32 certIndex = 0; PKIX_UInt32 anchorIndex = 0; PKIX_UInt32 checkerIndex = 0; PKIX_Boolean revChecking = PKIX_FALSE; PKIX_List *checkers = NULL; PRPollDesc *pollDesc = NULL; PRErrorCode errorCode = 0; PKIX_PL_Socket *socket = NULL; char *ldapName = NULL; PKIX_VerifyNode *verifyTree = NULL; PKIX_PL_String *verifyString = NULL; PKIX_List *loggers = NULL; PKIX_Logger *logger = NULL; char *logging = NULL; PKIX_PL_String *component = NULL; PKIX_TEST_STD_VARS(); if (argc < 5) { printUsage(); return (0); } startTests("ValidateChain_NB"); PKIX_TEST_EXPECT_NO_ERROR( PKIX_PL_NssContext_Create(0, PKIX_FALSE, NULL, &plContext)); /* ENE = expect no error; EE = expect error */ if (PORT_Strcmp(argv[2+j], "ENE") == 0) { testValid = PKIX_TRUE; } else if (PORT_Strcmp(argv[2+j], "EE") == 0) { testValid = PKIX_FALSE; } else { printUsage(); return (0); } subTest(argv[1+j]); dirName = argv[3+j]; chainLength = argc - j - 5; PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_Create(&chainCerts, plContext)); for (k = 0; k < chainLength; k++){ dirCert = createCert(dirName, argv[5+k+j], plContext); PKIX_TEST_EXPECT_NO_ERROR (PKIX_List_AppendItem (chainCerts, (PKIX_PL_Object *)dirCert, plContext)); PKIX_TEST_DECREF_BC(dirCert); } valParams = createValidateParams (dirName, argv[4+j], NULL, NULL, NULL, PKIX_FALSE, PKIX_FALSE, PKIX_FALSE, PKIX_FALSE, chainCerts, plContext); ldapName = PR_GetEnv("LDAP"); /* Is LDAP set in the environment? */ if ((ldapName == NULL) || (*ldapName == '\0')) { testError("LDAP not set in environment"); goto cleanup; } pkixTestErrorResult = pkix_pl_Socket_CreateByName (PKIX_FALSE, /* isServer */ PR_SecondsToInterval(30), /* try 30 secs for connect */ ldapName, &errorCode, &socket, plContext); if (pkixTestErrorResult != NULL) { PKIX_PL_Object_DecRef ((PKIX_PL_Object *)pkixTestErrorResult, plContext); pkixTestErrorResult = NULL; testError("Unable to connect to LDAP Server"); goto cleanup; } PKIX_TEST_DECREF_BC(socket); testSetupCertStore(valParams, ldapName); logging = PR_GetEnv("LOGGING"); /* Is LOGGING set in the environment? */ if ((logging != NULL) && (*logging != '\0')) { PKIX_TEST_EXPECT_NO_ERROR (PKIX_List_Create(&loggers, plContext)); testLogErrors (PKIX_VALIDATE_ERROR, 2, loggers, plContext); testLogErrors (PKIX_CERTCHAINCHECKER_ERROR, 2, loggers, plContext); testLogErrors (PKIX_LDAPDEFAULTCLIENT_ERROR, 2, loggers, plContext); testLogErrors (PKIX_CERTSTORE_ERROR, 2, loggers, plContext); PKIX_TEST_EXPECT_NO_ERROR(PKIX_SetLoggers(loggers, plContext)); } pkixTestErrorResult = PKIX_ValidateChain_NB (valParams, &certIndex, &anchorIndex, &checkerIndex, &revChecking, &checkers, (void **)&pollDesc, &valResult, &verifyTree, plContext); while (pollDesc != NULL) { if (PR_Poll(pollDesc, 1, 0) < 0) { testError("PR_Poll failed"); } pkixTestErrorResult = PKIX_ValidateChain_NB (valParams, &certIndex, &anchorIndex, &checkerIndex, &revChecking, &checkers, (void **)&pollDesc, &valResult, &verifyTree, plContext); } if (pkixTestErrorResult) { if (testValid == PKIX_FALSE) { /* EE */ (void) printf("EXPECTED ERROR RECEIVED!\n"); } else { /* ENE */ testError("UNEXPECTED ERROR RECEIVED"); } PKIX_TEST_DECREF_BC(pkixTestErrorResult); } else { if (testValid == PKIX_TRUE) { /* ENE */ (void) printf("EXPECTED NON-ERROR RECEIVED!\n"); } else { /* EE */ (void) printf("UNEXPECTED NON-ERROR RECEIVED!\n"); } } cleanup: if (verifyTree) { PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Object_ToString ((PKIX_PL_Object*)verifyTree, &verifyString, plContext)); (void) printf("verifyTree is\n%s\n", verifyString->escAsciiString); } PKIX_TEST_DECREF_AC(verifyString); PKIX_TEST_DECREF_AC(verifyTree); PKIX_TEST_DECREF_AC(checkers); PKIX_TEST_DECREF_AC(chainCerts); PKIX_TEST_DECREF_AC(valParams); PKIX_TEST_DECREF_AC(valResult); PKIX_Shutdown(plContext); PKIX_TEST_RETURN(); endTests("ValidateChain_NB"); return (0); }
/* * FUNCTION: pkix_Logger_CheckErrors * DESCRIPTION: * * This function goes through each PKIX_Logger at "pkixLoggersList" and * checks if "maxLevel" and "logComponent" satisfies what is specified in the * PKIX_Logger. If satisfies, it invokes the callback in PKIX_Logger and * passes a PKIX_PL_String that is the concatenation of "message" and * "message2" to the application for processing. * Since this call is inserted into a handful of PKIX macros, no macros are * applied in this function, to avoid infinite recursion. * If an error occurs, this call is aborted. * * PARAMETERS: * "pkixLoggersList" * A list of PKIX_Loggers to be examined for invoking callback. Must be * non-NULL. * "message" * Address of "message" to be logged. Must be non-NULL. * "message2" * Address of "message2" to be concatenated and logged. May be NULL. * "logComponent" * A PKIX_UInt32 that indicates the component the message is from. * "maxLevel" * A PKIX_UInt32 that represents the level of severity of the message. * "plContext" * Platform-specific context pointer. * THREAD SAFETY: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) * RETURNS: * Returns NULL if the function succeeds * Returns a Fatal Error if the function fails in an unrecoverable way */ PKIX_Error * pkix_Logger_Check( PKIX_List *pkixLoggersList, const char *message, const char *message2, PKIX_ERRORCLASS logComponent, PKIX_UInt32 currentLevel, void *plContext) { PKIX_Logger *logger = NULL; PKIX_List *savedPkixLoggersErrors = NULL; PKIX_List *savedPkixLoggersDebugTrace = NULL; PKIX_PL_String *formatString = NULL; PKIX_PL_String *messageString = NULL; PKIX_PL_String *message2String = NULL; PKIX_PL_String *msgString = NULL; PKIX_Error *error = NULL; PKIX_Boolean needLogging = PKIX_FALSE; PKIX_UInt32 i, length; /* * We cannot use any the PKIX_ macros here, since this function is * called from some of these macros. It can create infinite recursion. */ if ((pkixLoggersList == NULL) || (message == NULL)) { return(NULL); } /* * Disable all subsequent loggings to avoid recursion. The result is * if other thread is calling this function at the same time, there * won't be any logging because the pkixLoggersErrors and * pkixLoggersDebugTrace are set to null. * It would be nice if we provide control per thread (e.g. make * plContext threadable) then we can avoid the recursion by setting * flag at plContext. Then other thread's logging won't be affected. * * Also we need to use a reentrant Lock. Although we avoid recursion * for TRACE. When there is an ERROR occurs in subsequent call, this * function will be called. */ error = PKIX_PL_MonitorLock_Enter(pkixLoggerLock, plContext); if (error) { return(NULL); } savedPkixLoggersDebugTrace = pkixLoggersDebugTrace; pkixLoggersDebugTrace = NULL; savedPkixLoggersErrors = pkixLoggersErrors; pkixLoggersErrors = NULL; /* Convert message and message2 to String */ error = PKIX_PL_String_Create (PKIX_ESCASCII, message, 0, &messageString, plContext); if (error) { goto cleanup; } if (message2) { error = PKIX_PL_String_Create (PKIX_ESCASCII, message2, 0, &message2String, plContext); if (error) { goto cleanup; } error = PKIX_PL_String_Create (PKIX_ESCASCII, "%s %s", 0, &formatString, plContext); if (error) { goto cleanup; } } else { error = PKIX_PL_String_Create (PKIX_ESCASCII, "%s", 0, &formatString, plContext); if (error) { goto cleanup; } } error = PKIX_PL_Sprintf (&msgString, plContext, formatString, messageString, message2String); if (error) { goto cleanup; } /* Go through the Logger list */ error = PKIX_List_GetLength(pkixLoggersList, &length, plContext); if (error) { goto cleanup; } for (i = 0; i < length; i++) { error = PKIX_List_GetItem (pkixLoggersList, i, (PKIX_PL_Object **) &logger, plContext); if (error) { goto cleanup; } /* Intended logging level less or equal than the max */ needLogging = (currentLevel <= logger->maxLevel); if (needLogging && (logger->callback)) { /* * We separate Logger into two lists based on log level * but log level is not modified. We need to check here to * avoid logging the higher log level (lower value) twice. */ if (pkixLoggersList == pkixLoggersErrors) { needLogging = needLogging && (currentLevel <= PKIX_LOGGER_LEVEL_WARNING); } else if (pkixLoggersList == pkixLoggersDebugTrace) { needLogging = needLogging && (currentLevel > PKIX_LOGGER_LEVEL_WARNING); } if (needLogging) { if (logComponent == logger->logComponent) { needLogging = PKIX_TRUE; } else { needLogging = PKIX_FALSE; } } if (needLogging) { error = logger->callback (logger, msgString, currentLevel, logComponent, plContext); if (error) { goto cleanup; } } } error = PKIX_PL_Object_DecRef ((PKIX_PL_Object *)logger, plContext); logger = NULL; if (error) { goto cleanup; } } cleanup: if (formatString) { error = PKIX_PL_Object_DecRef ((PKIX_PL_Object *)formatString, plContext); } if (messageString) { error = PKIX_PL_Object_DecRef ((PKIX_PL_Object *)messageString, plContext); } if (message2String) { error = PKIX_PL_Object_DecRef ((PKIX_PL_Object *)message2String, plContext); } if (msgString) { error = PKIX_PL_Object_DecRef ((PKIX_PL_Object *)msgString, plContext); } if (logger) { error = PKIX_PL_Object_DecRef ((PKIX_PL_Object *)logger, plContext); } if (pkixLoggersErrors == NULL && savedPkixLoggersErrors != NULL) { pkixLoggersErrors = savedPkixLoggersErrors; } if (pkixLoggersDebugTrace == NULL && savedPkixLoggersDebugTrace != NULL) { pkixLoggersDebugTrace = savedPkixLoggersDebugTrace; } error = PKIX_PL_MonitorLock_Exit(pkixLoggerLock, plContext); if (error) { return(NULL); } return(NULL); }
/* * The OCSPChecker is created in an idle state, and remains in this state until * either (a) the default Responder has been set and enabled, and a Check * request is received with no responder specified, or (b) a Check request is * received with a specified responder. A request message is constructed and * given to the HttpClient. When a response is received it is decoded and the * results provided to the caller. * * During the most recent enhancement of this function, it has been found that * it doesn't correctly implement non-blocking I/O. * * The nbioContext is used in two places, for "response-obtaining" and * for "response-verification". * * However, if this function gets called to resume, it always * repeats the "request creation" and "response fetching" steps! * As a result, the earlier operation is never resumed. */ PKIX_Error * pkix_OcspChecker_CheckExternal( PKIX_PL_Cert *cert, PKIX_PL_Cert *issuer, PKIX_PL_Date *date, pkix_RevocationMethod *checkerObject, PKIX_ProcessingParams *procParams, PKIX_UInt32 methodFlags, PKIX_RevocationStatus *pRevStatus, CERTCRLEntryReasonCode *pReasonCode, void **pNBIOContext, void *plContext) { SECErrorCodes resultCode = SEC_ERROR_REVOKED_CERTIFICATE_OCSP; PKIX_Boolean uriFound = PKIX_FALSE; PKIX_Boolean passed = PKIX_TRUE; pkix_OcspChecker *checker = NULL; PKIX_PL_OcspCertID *cid = NULL; PKIX_PL_OcspRequest *request = NULL; PKIX_PL_OcspResponse *response = NULL; PKIX_PL_Date *validity = NULL; PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; void *nbioContext = NULL; enum { stageGET, stagePOST } currentStage; PRBool retry = PR_FALSE; PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_CheckExternal"); PKIX_CHECK( pkix_CheckType((PKIX_PL_Object*)checkerObject, PKIX_OCSPCHECKER_TYPE, plContext), PKIX_OBJECTNOTOCSPCHECKER); checker = (pkix_OcspChecker *)checkerObject; PKIX_CHECK( PKIX_PL_OcspCertID_Create(cert, NULL, &cid, plContext), PKIX_OCSPCERTIDCREATEFAILED); /* create request */ PKIX_CHECK( pkix_pl_OcspRequest_Create(cert, cid, validity, NULL, methodFlags, &uriFound, &request, plContext), PKIX_OCSPREQUESTCREATEFAILED); if (uriFound == PKIX_FALSE) { /* no caching for certs lacking URI */ resultCode = 0; goto cleanup; } if (methodFlags & CERT_REV_M_FORCE_POST_METHOD_FOR_OCSP) { /* Do not try HTTP GET, only HTTP POST */ currentStage = stagePOST; } else { /* Try HTTP GET first, falling back to POST */ currentStage = stageGET; } do { const char *method; passed = PKIX_TRUE; retry = PR_FALSE; if (currentStage == stageGET) { method = "GET"; } else { PORT_Assert(currentStage == stagePOST); method = "POST"; } /* send request and create a response object */ PKIX_CHECK_NO_GOTO( pkix_pl_OcspResponse_Create(request, method, NULL, checker->certVerifyFcn, &nbioContext, &response, plContext), PKIX_OCSPRESPONSECREATEFAILED); if (pkixErrorResult) { passed = PKIX_FALSE; } if (passed && nbioContext != 0) { *pNBIOContext = nbioContext; goto cleanup; } if (passed){ PKIX_CHECK_NO_GOTO( pkix_pl_OcspResponse_Decode(response, &passed, &resultCode, plContext), PKIX_OCSPRESPONSEDECODEFAILED); if (pkixErrorResult) { passed = PKIX_FALSE; } } if (passed){ PKIX_CHECK_NO_GOTO( pkix_pl_OcspResponse_GetStatus(response, &passed, &resultCode, plContext), PKIX_OCSPRESPONSEGETSTATUSRETURNEDANERROR); if (pkixErrorResult) { passed = PKIX_FALSE; } } if (passed){ PKIX_CHECK_NO_GOTO( pkix_pl_OcspResponse_VerifySignature(response, cert, procParams, &passed, &nbioContext, plContext), PKIX_OCSPRESPONSEVERIFYSIGNATUREFAILED); if (pkixErrorResult) { passed = PKIX_FALSE; } else { if (nbioContext != 0) { *pNBIOContext = nbioContext; goto cleanup; } } } if (!passed && currentStage == stagePOST) { /* We won't retry a POST failure, so it's final. * Because the following block with its call to * pkix_pl_OcspResponse_GetStatusForCert * will take care of caching good or bad state, * but we only execute that next block if there hasn't * been a failure yet, we must cache the POST * failure now. */ if (cid && cid->certID) { /* Caching MIGHT consume the cid. */ PKIX_Error *err; err = PKIX_PL_OcspCertID_RememberOCSPProcessingFailure( cid, plContext); if (err) { PKIX_PL_Object_DecRef((PKIX_PL_Object*)err, plContext); } } } if (passed){ PKIX_Boolean allowCachingOfFailures = (currentStage == stagePOST) ? PKIX_TRUE : PKIX_FALSE; PKIX_CHECK_NO_GOTO( pkix_pl_OcspResponse_GetStatusForCert(cid, response, allowCachingOfFailures, date, &passed, &resultCode, plContext), PKIX_OCSPRESPONSEGETSTATUSFORCERTFAILED); if (pkixErrorResult) { passed = PKIX_FALSE; } else if (passed == PKIX_FALSE) { revStatus = pkix_OcspChecker_MapResultCodeToRevStatus(resultCode); } else { revStatus = PKIX_RevStatus_Success; } } if (currentStage == stageGET && revStatus != PKIX_RevStatus_Success && revStatus != PKIX_RevStatus_Revoked) { /* we'll retry */ PKIX_DECREF(response); retry = PR_TRUE; currentStage = stagePOST; revStatus = PKIX_RevStatus_NoInfo; if (pkixErrorResult) { PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult, plContext); pkixErrorResult = NULL; } } } while (retry); cleanup: if (revStatus == PKIX_RevStatus_NoInfo && (uriFound || methodFlags & PKIX_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE) && methodFlags & PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO) { revStatus = PKIX_RevStatus_Revoked; } *pRevStatus = revStatus; /* ocsp carries only three statuses: good, bad, and unknown. * revStatus is used to pass them. reasonCode is always set * to be unknown. */ *pReasonCode = crlEntryReasonUnspecified; PKIX_DECREF(cid); PKIX_DECREF(request); PKIX_DECREF(response); PKIX_RETURN(OCSPCHECKER); }
/* * The OCSPChecker is created in an idle state, and remains in this state until * either (a) the default Responder has been set and enabled, and a Check * request is received with no responder specified, or (b) a Check request is * received with a specified responder. A request message is constructed and * given to the HttpClient. If non-blocking I/O is used the client may return * with WOULDBLOCK, in which case the OCSPChecker returns the WOULDBLOCK * condition to its caller in turn. On a subsequent call the I/O is resumed. * When a response is received it is decoded and the results provided to the * caller. * */ static PKIX_Error * pkix_OcspChecker_Check( PKIX_PL_Object *checkerObject, PKIX_PL_Cert *cert, PKIX_ProcessingParams *procParams, void **pNBIOContext, PKIX_UInt32 *pResultCode, void *plContext) { SECErrorCodes resultCode = SEC_ERROR_REVOKED_CERTIFICATE_OCSP; PKIX_Boolean uriFound = PKIX_FALSE; PKIX_Boolean passed = PKIX_FALSE; PKIX_OcspChecker *checker = NULL; PKIX_PL_OcspCertID *cid = NULL; PKIX_PL_OcspRequest *request = NULL; PKIX_PL_Date *validity = NULL; void *nbioContext = NULL; PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_Check"); PKIX_NULLCHECK_FOUR(checkerObject, cert, pNBIOContext, pResultCode); PKIX_CHECK(pkix_CheckType (checkerObject, PKIX_OCSPCHECKER_TYPE, plContext), PKIX_OBJECTNOTOCSPCHECKER); checker = (PKIX_OcspChecker *)checkerObject; nbioContext = *pNBIOContext; *pNBIOContext = 0; /* assert(checker->nbioContext == nbioContext) */ if (nbioContext == 0) { /* We are initiating a check, not resuming previous I/O. */ PKIX_Boolean hasFreshStatus = PKIX_FALSE; PKIX_Boolean statusIsGood = PKIX_FALSE; PKIX_CHECK(PKIX_PL_OcspCertID_Create (cert, validity, &cid, plContext), PKIX_OCSPCERTIDCREATEFAILED); if (!cid) { goto cleanup; } PKIX_CHECK(PKIX_PL_OcspCertID_GetFreshCacheStatus (cid, validity, &hasFreshStatus, &statusIsGood, &resultCode, plContext), PKIX_OCSPCERTIDGETFRESHCACHESTATUSFAILED); if (hasFreshStatus) { /* avoid updating the cache with a cached result... */ passed = PKIX_TRUE; if (statusIsGood) { resultCode = 0; } goto cleanup; } PKIX_INCREF(cert); PKIX_DECREF(checker->cert); checker->cert = cert; /* create request */ PKIX_CHECK(pkix_pl_OcspRequest_Create (cert, cid, validity, PKIX_FALSE, /* PKIX_Boolean addServiceLocator */ NULL, /* PKIX_PL_Cert *signerCert */ &uriFound, &request, plContext), PKIX_OCSPREQUESTCREATEFAILED); /* No uri to check is considered passing! */ if (uriFound == PKIX_FALSE) { /* no caching for certs lacking URI */ passed = PKIX_TRUE; resultCode = 0; goto cleanup; } } /* Do we already have a response object? */ if ((checker->response) == NULL) { /* send request and create a response object */ PKIX_CHECK(pkix_pl_OcspResponse_Create (request, checker->responder, checker->verifyFcn, &nbioContext, &(checker->response), plContext), PKIX_OCSPRESPONSECREATEFAILED); if (nbioContext != 0) { *pNBIOContext = nbioContext; goto cleanup; } PKIX_CHECK(pkix_pl_OcspResponse_Decode ((checker->response), &passed, &resultCode, plContext), PKIX_OCSPRESPONSEDECODEFAILED); if (passed == PKIX_FALSE) { goto cleanup; } PKIX_CHECK(pkix_pl_OcspResponse_GetStatus ((checker->response), &passed, &resultCode, plContext), PKIX_OCSPRESPONSEGETSTATUSRETURNEDANERROR); if (passed == PKIX_FALSE) { goto cleanup; } } PKIX_CHECK(pkix_pl_OcspResponse_VerifySignature ((checker->response), cert, procParams, &passed, &nbioContext, plContext), PKIX_OCSPRESPONSEVERIFYSIGNATUREFAILED); if (nbioContext != 0) { *pNBIOContext = nbioContext; goto cleanup; } if (passed == PKIX_FALSE) { resultCode = PORT_GetError(); goto cleanup; } PKIX_CHECK(pkix_pl_OcspResponse_GetStatusForCert (cid, (checker->response), &passed, &resultCode, plContext), PKIX_OCSPRESPONSEGETSTATUSFORCERTFAILED); cleanup: if (!passed && cid && cid->certID && !cid->certIDWasConsumed) { /* We still own the certID object, which means that * it did not get consumed to create a cache entry. * Let's make sure we create one. */ PKIX_Error *err; err = PKIX_PL_OcspCertID_RememberOCSPProcessingFailure( cid, plContext); if (err) { PKIX_PL_Object_DecRef((PKIX_PL_Object*)err, plContext); } } *pResultCode = (PKIX_UInt32)resultCode; PKIX_DECREF(cid); PKIX_DECREF(request); if (checker) { PKIX_DECREF(checker->response); } PKIX_RETURN(OCSPCHECKER); }
static PKIX_PL_Cert * createCert(char *inFileName) { PKIX_PL_ByteArray *byteArray = NULL; PKIX_PL_Cert *cert = NULL; PKIX_Error *error = NULL; PRFileDesc *inFile = NULL; SECItem certDER; void *buf = NULL; PKIX_UInt32 len; SECStatus rv = SECFailure; certDER.data = NULL; inFile = PR_Open(inFileName, PR_RDONLY, 0); if (!inFile){ printFailure("Unable to open cert file"); goto cleanup; } else { rv = SECU_ReadDERFromFile(&certDER, inFile, PR_FALSE); if (!rv){ buf = (void *)certDER.data; len = certDER.len; error = PKIX_PL_ByteArray_Create (buf, len, &byteArray, plContext); if (error){ printFailure("PKIX_PL_ByteArray_Create failed"); goto cleanup; } error = PKIX_PL_Cert_Create (byteArray, &cert, plContext); if (error){ printFailure("PKIX_PL_Cert_Create failed"); goto cleanup; } } else { printFailure("Unable to read DER from cert file"); goto cleanup; } } cleanup: if (inFile){ PR_Close(inFile); } if (rv == SECSuccess){ SECITEM_FreeItem(&certDER, PR_FALSE); } if (byteArray){ PKIX_PL_Object_DecRef((PKIX_PL_Object *)(byteArray), plContext); } return (cert); }
int dumpcert(int argc, char *argv[]) { PKIX_PL_String *string = NULL; PKIX_PL_Cert *cert = NULL; PKIX_Error *error = NULL; char *ascii = NULL; PKIX_UInt32 length = 0; PKIX_UInt32 j = 0; PKIX_Boolean useArenas = PKIX_FALSE; PKIX_UInt32 actualMinorVersion; PKIX_TEST_STD_VARS(); if (argc == 1){ printUsage(); return (0); } useArenas = PKIX_TEST_ARENAS_ARG(argv[1]); PKIX_Initialize (PKIX_TRUE, /* nssInitNeeded */ useArenas, PKIX_MAJOR_VERSION, PKIX_MINOR_VERSION, PKIX_MINOR_VERSION, &actualMinorVersion, &plContext); cert = createCert(argv[1+j]); if (cert){ error = PKIX_PL_Object_ToString ((PKIX_PL_Object *)cert, &string, plContext); if (error){ printFailure("Unable to get string representation " "of cert"); goto cleanup; } error = PKIX_PL_String_GetEncoded (string, PKIX_ESCASCII, (void **)&ascii, &length, plContext); if (error || !ascii){ printFailure("Unable to get ASCII encoding of string"); goto cleanup; } (void) printf("OUTPUT:\n%s\n", ascii); } else { printFailure("Unable to create certificate"); goto cleanup; } cleanup: if (cert){ PKIX_PL_Object_DecRef((PKIX_PL_Object *)(cert), plContext); } if (string){ PKIX_PL_Object_DecRef((PKIX_PL_Object *)(string), plContext); } if (ascii){ PKIX_PL_Free((PKIX_PL_Object *)(ascii), plContext); } PKIX_Shutdown(plContext); PKIX_TEST_RETURN(); endTests("DUMPCERT"); return (0); }