/* * 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); }
/* * 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); }