Exemplo n.º 1
0
/*
 * 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;
}
Exemplo n.º 2
0
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);
}
Exemplo n.º 5
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);
}
Exemplo n.º 6
0
/*
 * 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);
}
Exemplo n.º 7
0
/*
 * 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);
}