Esempio n. 1
0
/*
 * FUNCTION: pkix_pl_HttpCertStore_ProcessCertResponse
 * DESCRIPTION:
 *
 *  This function verifies that the response code pointed to by "responseCode"
 *  and the content type pointed to by "responseContentType" are as expected,
 *  and then decodes the data pointed to by "responseData", of length
 *  "responseDataLen", into a List of Certs, possibly empty, which is returned
 *  at "pCertList".
 *
 * PARAMETERS:
 *  "responseCode"
 *      The value of the HTTP response code.
 *  "responseContentType"
 *      The address of the Content-type string. Must be non-NULL.
 *  "responseData"
 *      The address of the message data. Must be non-NULL.
 *  "responseDataLen"
 *      The length of the message data.
 *  "pCertList"
 *      The address of the List that is created. Must be non-NULL.
 *  "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 HttpCertStore Error if the function fails in a non-fatal way.
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
 */
PKIX_Error *
pkix_pl_HttpCertStore_ProcessCertResponse(
        PRUint16 responseCode,
        const char *responseContentType,
        const char *responseData,
        PRUint32 responseDataLen,
        PKIX_List **pCertList,
        void *plContext)
{
        callbackContext cbContext;

        PKIX_ENTER(HTTPCERTSTORECONTEXT,
                "pkix_pl_HttpCertStore_ProcessCertResponse");
        
        cbContext.error = NULL;
        cbContext.plContext = plContext;
        cbContext.pkixCertList = NULL;

        PKIX_NULLCHECK_ONE(pCertList);

        if (responseCode != 200) {
                PKIX_ERROR(PKIX_BADHTTPRESPONSE);
        }

        /* check that response type is application/pkcs7-mime */
        if (responseContentType == NULL) {
                PKIX_ERROR(PKIX_NOCONTENTTYPEINHTTPRESPONSE);
        }

        if (responseData == NULL) {
                PKIX_ERROR(PKIX_NORESPONSEDATAINHTTPRESPONSE);
        }

        PKIX_CHECK(
            PKIX_List_Create(&cbContext.pkixCertList, plContext),
            PKIX_LISTCREATEFAILED);
        
        PKIX_CHECK_ONLY_FATAL(
            pkix_pl_HttpCertStore_DecodeCertPackage(responseData,
                                                    responseDataLen,
                                                    certCallback,
                                                    &cbContext,
                                                    plContext),
            PKIX_HTTPCERTSTOREDECODECERTPACKAGEFAILED);
        if (cbContext.error) {
            /* Aborting on a fatal error(See certCallback fn) */
            pkixErrorResult = cbContext.error;
            goto cleanup;
        }
        
        *pCertList = cbContext.pkixCertList;
        cbContext.pkixCertList = NULL;

cleanup:

        PKIX_DECREF(cbContext.pkixCertList);

        PKIX_RETURN(HTTPCERTSTORECONTEXT);
}
/*
 * FUNCTION: pkix_pl_CollectionCertStoreContext_GetSelectedCRL
 * DESCRIPTION:
 *
 *  Finds the CRLs that match the criterion of the CRLSelector pointed
 *  to by "selector" using the List of CRLs pointed to by "crlList" and
 *  stores the matching CRLs at "pSelectedCrlList".
 *
 *  Not recursive to sub-directory.
 *
 * PARAMETERS
 *  "crlList" - Address of List of CRLs to be searched. Must be non-NULL
 *  "selector" - CRLSelector for chosing CRL based on Params set
 *  "pSelectedCrlList" - CRLs that qualified by selector.
 *  "plContext" - Platform-specific context pointer.
 *
 * THREAD SAFETY:
 *  Not Thread Safe - A lock at top level is required.
 *
 * RETURNS:
 *  Returns NULL if the function succeeds.
 *  Returns a CollectionCertStoreContext Error if the function fails in
 *              a non-fatal way.
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
 */
static PKIX_Error *
pkix_pl_CollectionCertStoreContext_GetSelectedCRL(
        PKIX_List *crlList,
        PKIX_CRLSelector *selector,
        PKIX_List **pSelectedCrlList,
        void *plContext)
{
        PKIX_List *selectCrlList = NULL;
        PKIX_PL_CRL *crlItem = NULL;
        PKIX_CRLSelector_MatchCallback crlSelectorMatch = NULL;
        PKIX_UInt32 numCrls = 0;
        PKIX_UInt32 i = 0;
        PKIX_Boolean match = PKIX_FALSE;

        PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
                    "pkix_pl_CollectionCertStoreContext_GetSelectedCRL");
        PKIX_NULLCHECK_THREE(crlList, selector, pSelectedCrlList);

        PKIX_CHECK(PKIX_CRLSelector_GetMatchCallback
                    (selector, &crlSelectorMatch, plContext),
                    PKIX_CRLSELECTORGETMATCHCALLBACKFAILED);

        PKIX_CHECK(PKIX_List_GetLength(crlList, &numCrls, plContext),
                    PKIX_LISTGETLENGTHFAILED);

        if (crlSelectorMatch) {

                PKIX_CHECK(PKIX_List_Create(&selectCrlList, plContext),
                            PKIX_LISTCREATEFAILED);

                for (i = 0; i < numCrls; i++) {
                        PKIX_CHECK_ONLY_FATAL(PKIX_List_GetItem
                                (crlList,
                                i,
                                (PKIX_PL_Object **) &crlItem,
                                plContext),
                                PKIX_LISTGETITEMFAILED);

                        if (!PKIX_ERROR_RECEIVED){
                                PKIX_CHECK_ONLY_FATAL
                                        (crlSelectorMatch
                                        (selector, crlItem, &match, plContext),
                                        PKIX_CRLSELECTORMATCHFAILED);

                                if (!(PKIX_ERROR_RECEIVED) && match) {
                                        PKIX_CHECK_ONLY_FATAL
                                                (PKIX_List_AppendItem
                                                (selectCrlList,
                                                (PKIX_PL_Object *)crlItem,
                                                plContext),
                                                PKIX_LISTAPPENDITEMFAILED);
                                }
                        }

                        PKIX_DECREF(crlItem);
                }
        } else {

                PKIX_INCREF(crlList);

                selectCrlList = crlList;
        }

        /* Don't throw away the list if one CRL was bad! */
        pkixTempErrorReceived = PKIX_FALSE;

        *pSelectedCrlList = selectCrlList;

cleanup:
        PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
}
/*
 * FUNCTION: pkix_pl_CollectionCertStoreContext_GetSelectedCert
 * DESCRIPTION:
 *
 *  Finds the Certs that match the criterion of the CertSelector pointed
 *  to by "selector" using the List of Certs pointed to by "certList" and
 *  stores the matching Certs at "pSelectedCertList".
 *
 *  Not recursive to sub-directory.
 *
 * PARAMETERS
 *  "certList" - Address of List of Certs to be searched. Must be non-NULL.
 *  "colCertStoreContext" - Address of CollectionCertStoreContext
 *              where the cached Certs are stored.
 *  "selector" - CertSelector for chosing Cert based on Params set
 *  "pSelectedCertList" - Certs that qualified by selector.
 *  "plContext" - Platform-specific context pointer.
 *
 * THREAD SAFETY:
 *  Not Thread Safe - A lock at top level is required.
 *
 * RETURNS:
 *  Returns NULL if the function succeeds.
 *  Returns a CollectionCertStoreContext Error if the function fails in
 *              a non-fatal way.
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
 */
static PKIX_Error *
pkix_pl_CollectionCertStoreContext_GetSelectedCert(
        PKIX_List *certList,
        PKIX_CertSelector *selector,
        PKIX_List **pSelectedCertList,
        void *plContext)
{
        PKIX_List *selectCertList = NULL;
        PKIX_PL_Cert *certItem = NULL;
        PKIX_CertSelector_MatchCallback certSelectorMatch = NULL;
        PKIX_UInt32 numCerts = 0;
        PKIX_UInt32 i = 0;

        PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
                    "pkix_pl_CollectionCertStoreContext_GetSelectedCert");
        PKIX_NULLCHECK_THREE(certList, selector, pSelectedCertList);

        PKIX_CHECK(PKIX_CertSelector_GetMatchCallback
                    (selector, &certSelectorMatch, plContext),
                    PKIX_CERTSELECTORGETMATCHCALLBACKFAILED);

        PKIX_CHECK(PKIX_List_GetLength(certList, &numCerts, plContext),
                    PKIX_LISTGETLENGTHFAILED);

        if (certSelectorMatch) {

                PKIX_CHECK(PKIX_List_Create(&selectCertList, plContext),
                            PKIX_LISTCREATEFAILED);

                for (i = 0; i < numCerts; i++) {
                        PKIX_CHECK_ONLY_FATAL
                                (PKIX_List_GetItem
                                (certList,
                                i,
                                (PKIX_PL_Object **) &certItem,
                                plContext),
                                PKIX_LISTGETITEMFAILED);

                        if (!PKIX_ERROR_RECEIVED){
                                PKIX_CHECK_ONLY_FATAL
                                        (certSelectorMatch
                                        (selector, certItem, plContext),
                                        PKIX_CERTSELECTORMATCHFAILED);

                                if (!PKIX_ERROR_RECEIVED){
                                        PKIX_CHECK_ONLY_FATAL
                                                (PKIX_List_AppendItem
                                                (selectCertList,
                                                (PKIX_PL_Object *)certItem,
                                                plContext),
                                                PKIX_LISTAPPENDITEMFAILED);
                                }
                        }

                        PKIX_DECREF(certItem);
                }

        } else {

                PKIX_INCREF(certList);

                selectCertList = certList;
        }

        *pSelectedCertList = selectCertList;

cleanup:
        PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
}
/*
 * FUNCTION: pkix_pl_CollectionCertStoreContext_PopulateCRL
 * DESCRIPTION:
 *
 *  Create list of CRLs from *.crl files at directory specified in dirName,
 *  Not recursive to sub-dirctory. Also assume the directory contents are
 *  not changed dynamically.
 *
 * PARAMETERS
 *  "colCertStoreContext" - Address of CollectionCertStoreContext
 *              where the dirName is specified and where the return
 *              CRLs are stored as a list. Must be non-NULL.
 *  "plContext" - Platform-specific context pointer.
 *
 * THREAD SAFETY:
 *  Not Thread Safe - A lock at top level is required.
 *
 * RETURNS:
 *  Returns NULL if the function succeeds.
 *  Returns a CollectionCertStoreContext Error if the function fails in
 *              a non-fatal way.
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
 */
static PKIX_Error *
pkix_pl_CollectionCertStoreContext_PopulateCRL(
        PKIX_PL_CollectionCertStoreContext *colCertStoreContext,
        void *plContext)
{
        PKIX_List *crlList = NULL;
        PKIX_PL_CRL *crlItem = NULL;
        char *dirName = NULL;
        char *pathName = NULL;
        PKIX_UInt32 dirNameLen = 0;
        PRErrorCode prError = 0;
        PRDir *dir = NULL;
        PRDirEntry *dirEntry = NULL;

        PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
                    "pkix_pl_CollectionCertStoreContext_PopulateCRL");
        PKIX_NULLCHECK_ONE(colCertStoreContext);

        /* convert directory to ascii */

        PKIX_CHECK(PKIX_PL_String_GetEncoded
                    (colCertStoreContext->storeDir,
                    PKIX_ESCASCII,
                    (void **)&dirName,
                    &dirNameLen,
                    plContext),
                    PKIX_STRINGGETENCODEDFAILED);

        /* create CRL list, if no CRL file, should return an empty list */

        PKIX_CHECK(PKIX_List_Create(&crlList, plContext),
                    PKIX_LISTCREATEFAILED);

        /* open directory and read in .crl files */

        PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_OpenDir.\n");
        dir = PR_OpenDir(dirName);

        if (!dir) {
                PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG_ARG
                        ("\t\t Directory Name:%s\n", dirName);
                PKIX_ERROR(PKIX_CANNOTOPENCOLLECTIONCERTSTORECONTEXTDIRECTORY);
        }

        PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_ReadDir.\n");
        dirEntry = PR_ReadDir(dir, PR_SKIP_HIDDEN | PR_SKIP_BOTH);

        if (!dirEntry) {
                PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
                        ("\t\t Empty directory.\n");
                PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
                        ("\t\t Calling PR_GetError.\n");
                prError = PR_GetError();
        }

        PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_SetError.\n");
        PR_SetError(0, 0);

        while (dirEntry != NULL && prError == 0) {
                if (PL_strrstr(dirEntry->name, ".crl") ==
                    dirEntry->name + PL_strlen(dirEntry->name) - 4) {

                        PKIX_CHECK_ONLY_FATAL
                                (PKIX_PL_Malloc
                                (dirNameLen + PL_strlen(dirEntry->name) + 2,
                                (void **)&pathName,
                                plContext),
                                PKIX_MALLOCFAILED);

                        if ((!PKIX_ERROR_RECEIVED) && (pathName != NULL)){

                                PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
                                    ("\t\t Calling PL_strcpy for dirName.\n");
                                PL_strcpy(pathName, dirName);
                                PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
                                    ("\t\t Calling PL_strcat for dirName.\n");
                                PL_strcat(pathName, "/");
                                PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
                                        ("\t\t Calling PL_strcat for /.\n");
                                PL_strcat(pathName, dirEntry->name);

                        PKIX_CHECK_ONLY_FATAL
                                (pkix_pl_CollectionCertStoreContext_CreateCRL
                                (pathName, &crlItem, plContext),
                                PKIX_COLLECTIONCERTSTORECONTEXTCREATECRLFAILED);

                                if (!PKIX_ERROR_RECEIVED){
                                        PKIX_CHECK_ONLY_FATAL
                                                (PKIX_List_AppendItem
                                                (crlList,
                                                (PKIX_PL_Object *)crlItem,
                                                plContext),
                                                PKIX_LISTAPPENDITEMFAILED);
                                }
                        }

                        PKIX_DECREF(crlItem);
                        PKIX_FREE(pathName);
                }

                PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
                        ("\t\t Calling PR_SetError.\n");
                PR_SetError(0, 0);

                PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
                        ("\t\t Calling PR_ReadDir.\n");
                dirEntry = PR_ReadDir(dir, PR_SKIP_HIDDEN | PR_SKIP_BOTH);

                if (!dirEntry) {
                    PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
                        ("\t\t Calling PR_GetError.\n");
                    prError = PR_GetError();
                }
        }

        if ((prError != 0) && (prError != PR_NO_MORE_FILES_ERROR)) {
                PKIX_ERROR(PKIX_COLLECTIONCERTSTORECONTEXTGETSELECTCRLFAILED);
        }

        PKIX_CHECK(PKIX_List_SetImmutable(crlList, plContext),
                    PKIX_LISTSETIMMUTABLEFAILED);

        PKIX_INCREF(crlList);
        colCertStoreContext->crlList = crlList;

cleanup:
        if (dir) {
                PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
                        ("\t\t Calling PR_CloseDir.\n");
                PR_CloseDir(dir);
        }

        PKIX_FREE(pathName);
        PKIX_FREE(dirName);

        if (PKIX_ERROR_RECEIVED){
                PKIX_DECREF(crlList);
        }

        PKIX_DECREF(crlItem);
        PKIX_DECREF(crlList);

        PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
}
Esempio n. 5
0
/*
 * FUNCTION: pkix_pl_OcspResponse_VerifySignature
 * DESCRIPTION:
 *
 *  This function verifies the ocspResponse signature field in the OcspResponse
 *  pointed to by "response", storing PKIX_TRUE at "pPassed" if verification
 *  is successful and PKIX_FALSE otherwise. If verification is unsuccessful an
 *  error code (an enumeration of type SECErrorCodes) is stored at *pReturnCode.
 *
 * PARAMETERS
 *  "response"
 *      The address of the OcspResponse whose signature field is to be
 *      retrieved. Must be non-NULL.
 *  "cert"
 *      The address of the Cert for which the OCSP query was made. Must be
 *      non-NULL.
 *  "procParams"
 *      Address of ProcessingParams used to initialize the ExpirationChecker
 *      and TargetCertChecker. Must be non-NULL.
 *  "pPassed"
 *      Address at which the Boolean result is stored. Must be non-NULL.
 *  "pNBIOContext"
 *      Address at which the NBIOContext is stored indicating whether the
 *      checking is complete. Must be non-NULL.
 *  "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 an OcspResponse Error if the function fails in a non-fatal way.
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
 */
PKIX_Error *
pkix_pl_OcspResponse_VerifySignature(
        PKIX_PL_OcspResponse *response,
        PKIX_PL_Cert *cert,
        PKIX_ProcessingParams *procParams,
        PKIX_Boolean *pPassed,
        void **pNBIOContext,
        void *plContext)
{
        SECStatus rv = SECFailure;
        CERTOCSPResponse *nssOCSPResponse = NULL;
        CERTCertificate *issuerCert = NULL;
        PKIX_BuildResult *buildResult = NULL;
        void *nbio = NULL;
        void *state = NULL;

        ocspSignature *signature = NULL;
        ocspResponseData *tbsData = NULL;
        SECItem *tbsResponseDataDER = NULL;


        PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_VerifySignature");
        PKIX_NULLCHECK_FOUR(response, cert, pPassed,  pNBIOContext);

        nbio = *pNBIOContext;
        *pNBIOContext = NULL;

        nssOCSPResponse = response->nssOCSPResponse;
        if (nssOCSPResponse == NULL) {
            PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
            goto cleanup;
        }

        tbsData =
            ocsp_GetResponseData(nssOCSPResponse, &tbsResponseDataDER);
        
        signature = ocsp_GetResponseSignature(nssOCSPResponse);


        /* Are we resuming after a WOULDBLOCK response? */
        if (nbio == NULL) {
            /* No, this is a new query */

            issuerCert = CERT_FindCertIssuer(cert->nssCert, PR_Now(),
                                             certUsageAnyCA);
            
            /*
             * If this signature has already gone through verification,
             * just return the cached result.
             */
            if (signature->wasChecked) {
                if (signature->status == SECSuccess) {
                    response->signerCert =
                        CERT_DupCertificate(signature->cert);
                } else {
                    PORT_SetError(signature->failureReason);
                    goto cleanup;
                }
            }
            
            response->signerCert = 
                ocsp_GetSignerCertificate(response->handle, tbsData,
                                          signature, issuerCert);
            
            if (response->signerCert == NULL) {
                PORT_SetError(SEC_ERROR_UNKNOWN_SIGNER);
                goto cleanup;
            }
            
            PKIX_CHECK( 
                PKIX_PL_Cert_CreateFromCERTCertificate(response->signerCert,
                                                       &(response->pkixSignerCert),
                                                       plContext),
                PKIX_CERTCREATEWITHNSSCERTFAILED);
            
            /*
             * We could mark this true at the top of this function, or
             * always below at "finish", but if the problem was just that
             * we could not find the signer's cert, leave that as if the
             * signature hasn't been checked. Maybe a subsequent call will
             * have better luck.
             */
            signature->wasChecked = PR_TRUE;
            
            /*
             * We are about to verify the signer certificate; we need to
             * specify *when* that certificate must be valid -- for our
             * purposes we expect it to be valid when the response was
             * signed. The value of "producedAt" is the signing time.
             */
            rv = DER_GeneralizedTimeToTime(&response->producedAt,
                                           &tbsData->producedAt);
            if (rv != SECSuccess) {
                PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
                goto cleanup;
            }
            
            /*
             * We need producedAtDate and pkixSignerCert if we are calling a
             * user-supplied verification function. Let's put their
             * creation before the code that gets repeated when
             * non-blocking I/O is used.
             */
            
            PKIX_CHECK(
                pkix_pl_Date_CreateFromPRTime((PRTime)response->producedAt,
                                              &(response->producedAtDate),
                                              plContext),
                PKIX_DATECREATEFROMPRTIMEFAILED);
            
	}
        
        /*
         * Just because we have a cert does not mean it is any good; check
         * it for validity, trust and usage. Use the caller-supplied
         * verification function, if one was supplied.
         */
        if (ocsp_CertIsOCSPDefaultResponder(response->handle,
                                            response->signerCert)) {
            rv = SECSuccess;
        } else {
            SECCertUsage certUsage;
            if (CERT_IsCACert(response->signerCert, NULL)) {
                certUsage = certUsageAnyCA;
            } else {
                certUsage = certUsageStatusResponder;
            }
            PKIX_CHECK_ONLY_FATAL(
                pkix_pl_OcspResponse_VerifyResponse(response, procParams,
                                                    certUsage, &state,
                                                    &buildResult, &nbio,
                                                    plContext),
                PKIX_CERTVERIFYKEYUSAGEFAILED);
            if (pkixTempErrorReceived) {
                rv = SECFailure;
                goto cleanup;
            }
            if (nbio != NULL) {
                *pNBIOContext = nbio;
                goto cleanup;
            }            
        }

        rv = ocsp_VerifyResponseSignature(response->signerCert, signature,
                                          tbsResponseDataDER, NULL);
        
cleanup:
        if (rv == SECSuccess) {
            *pPassed = PKIX_TRUE;
        } else {
            *pPassed = PKIX_FALSE;
        }
        
        if (signature) {
            if (signature->wasChecked) {
                signature->status = rv;
            }
            
            if (rv != SECSuccess) {
                signature->failureReason = PORT_GetError();
                if (response->signerCert != NULL) {
                    CERT_DestroyCertificate(response->signerCert);
                    response->signerCert = NULL;
                }
            } else {
                /* Save signer's certificate in signature. */
                signature->cert = CERT_DupCertificate(response->signerCert);
            }
        }

	if (issuerCert)
	    CERT_DestroyCertificate(issuerCert);
        
        PKIX_RETURN(OCSPRESPONSE);
}