Example #1
0
bool
OCSPCache::Get(const CertID& aCertID, PRErrorCode& aErrorCode,
               PRTime& aValidThrough)
{
  MutexAutoLock lock(mMutex);

  size_t index;
  if (!FindInternal(aCertID, index, lock)) {
    LogWithCertID("OCSPCache::Get(%p) not in cache", aCertID);
    return false;
  }
  LogWithCertID("OCSPCache::Get(%p) in cache", aCertID);
  aErrorCode = mEntries[index]->mErrorCode;
  aValidThrough = mEntries[index]->mValidThrough;
  MakeMostRecentlyUsed(index, lock);
  return true;
}
/**
Search for a node by directory path, start from children of aNodeToStart but do not include aNodeToStart.

@param	aPath			the path as the key to search in the tree
@param	aNodeToStart	the node whose children to start with 
@param	aNodeFound		in return, the node found 
@param	aDirPos			the location of the directory
@return	KErrNone 		if a node found
		KErrNotFound 	if no node is found
*/
TInt CLeafDirTree::DoSearch(const TDesC& aPath, CLeafDirTreeNode* aNodeToStart, CLeafDirTreeNode*& aNodeFound, TLeafDirData& aLeafDirData)
	{
	RPointerArray<CLeafDirTreeNode> currentLevel = aNodeToStart->Children();
	TInt currentPos = currentLevel.Count() - 1;
	// Current path in search
	TPtrC currentPath;
	currentPath.Set(aPath);
	while (currentLevel.Count() > 0 && currentPos >= 0)
		{
		CLeafDirTreeNode* currentNode = currentLevel[currentPos];
		TPtrC currentNodePath;
		currentNodePath.Set(currentNode->Path());
		TInt foundPos = currentPath.FindF(currentNodePath);
		// If current child's path is part of the searching path, 
		// 	go to next level
		// 	E.g.: current child's path = "1\2\3\", searching path = "1\2\3\5\".
		if (foundPos == 0 && currentNodePath.Length() < currentPath.Length())
			{
			currentPath.Set(currentPath.Mid(currentNodePath.Length()));
			currentLevel = currentNode->Children();
			currentPos = currentLevel.Count() - 1;
			continue;
			}
		// If current child's path matches current searching path,
		// 	check the node type.
		else if (foundPos == 0 && currentNodePath.Length() == currentPath.Length())
			{
			if (currentNode->IsPureIntermediary())
			// If found is 'pure intermediary', it is not cached. 
				{
				return KErrNotFound;
				}
			// Otherwise, we have got a cache hit!
			MakeMostRecentlyUsed(currentNode);
			aNodeFound = currentNode;
			aLeafDirData = currentNode->LeafDirData();
			return KErrNone;
			}
		// else, go through current level
		currentPos--;
		}
	// If there is no child or we have not found any matching node,
	//	return KErrNotFound
	return KErrNotFound;
	}
Example #3
0
bool
OCSPCache::Get(const CERTCertificate* aCert,
               const CERTCertificate* aIssuerCert,
               PRErrorCode& aErrorCode,
               PRTime& aValidThrough)
{
  PR_ASSERT(aCert);
  PR_ASSERT(aIssuerCert);

  MutexAutoLock lock(mMutex);

  size_t index;
  if (!FindInternal(aCert, aIssuerCert, index, lock)) {
    LogWithCerts("OCSPCache::Get(%s, %s) not in cache", aCert, aIssuerCert);
    return false;
  }
  LogWithCerts("OCSPCache::Get(%s, %s) in cache", aCert, aIssuerCert);
  aErrorCode = mEntries[index]->mErrorCode;
  aValidThrough = mEntries[index]->mValidThrough;
  MakeMostRecentlyUsed(index, lock);
  return true;
}
Example #4
0
Result
OCSPCache::Put(const CertID& aCertID, Result aResult,
               Time aThisUpdate, Time aValidThrough)
{
  MutexAutoLock lock(mMutex);

  size_t index;
  if (FindInternal(aCertID, index, lock)) {
    // Never replace an entry indicating a revoked certificate.
    if (mEntries[index]->mResult == Result::ERROR_REVOKED_CERTIFICATE) {
      LogWithCertID("OCSPCache::Put(%p) already in cache as revoked - "
                    "not replacing", aCertID);
      MakeMostRecentlyUsed(index, lock);
      return Success;
    }

    // Never replace a newer entry with an older one unless the older entry
    // indicates a revoked certificate, which we want to remember.
    if (mEntries[index]->mThisUpdate > aThisUpdate &&
        aResult != Result::ERROR_REVOKED_CERTIFICATE) {
      LogWithCertID("OCSPCache::Put(%p) already in cache with more recent "
                    "validity - not replacing", aCertID);
      MakeMostRecentlyUsed(index, lock);
      return Success;
    }

    // Only known good responses or responses indicating an unknown
    // or revoked certificate should replace previously known responses.
    if (aResult != Success &&
        aResult != Result::ERROR_OCSP_UNKNOWN_CERT &&
        aResult != Result::ERROR_REVOKED_CERTIFICATE) {
      LogWithCertID("OCSPCache::Put(%p) already in cache - not replacing "
                    "with less important status", aCertID);
      MakeMostRecentlyUsed(index, lock);
      return Success;
    }

    LogWithCertID("OCSPCache::Put(%p) already in cache - replacing", aCertID);
    mEntries[index]->mResult = aResult;
    mEntries[index]->mThisUpdate = aThisUpdate;
    mEntries[index]->mValidThrough = aValidThrough;
    MakeMostRecentlyUsed(index, lock);
    return Success;
  }

  if (mEntries.length() == MaxEntries) {
    LogWithCertID("OCSPCache::Put(%p) too full - evicting an entry", aCertID);
    for (Entry** toEvict = mEntries.begin(); toEvict != mEntries.end();
         toEvict++) {
      // Never evict an entry that indicates a revoked or unknokwn certificate,
      // because revoked responses are more security-critical to remember.
      if ((*toEvict)->mResult != Result::ERROR_REVOKED_CERTIFICATE &&
          (*toEvict)->mResult != Result::ERROR_OCSP_UNKNOWN_CERT) {
        delete *toEvict;
        mEntries.erase(toEvict);
        break;
      }
    }
    // Well, we tried, but apparently everything is revoked or unknown.
    // We don't want to remove a cached revoked or unknown response. If we're
    // trying to insert a good response, we can just return "successfully"
    // without doing so. This means we'll lose some speed, but it's not a
    // security issue. If we're trying to insert a revoked or unknown response,
    // we can't. We should return with an error that causes the current
    // verification to fail.
    if (mEntries.length() == MaxEntries) {
      return aResult;
    }
  }

  Entry* newEntry = new (std::nothrow) Entry(aResult, aThisUpdate,
                                             aValidThrough);
  // Normally we don't have to do this in Gecko, because OOM is fatal.
  // However, if we want to embed this in another project, OOM might not
  // be fatal, so handle this case.
  if (!newEntry) {
    return Result::FATAL_ERROR_NO_MEMORY;
  }
  Result rv = newEntry->Init(aCertID);
  if (rv != Success) {
    delete newEntry;
    return rv;
  }
  if (!mEntries.append(newEntry)) {
    delete newEntry;
    return Result::FATAL_ERROR_NO_MEMORY;
  }
  LogWithCertID("OCSPCache::Put(%p) added to cache", aCertID);
  return Success;
}
/**
Implementation of the insertion algorithm 

@param	aNodeToStart	the node whose children to start with
@param	aPath			the path of the new node to be inserted
@param	aDirPos 		the position of the new node to be inserted
@param	aNodeInserted 	in return, the node that has been successfully inserted
*/
void CLeafDirTree::DoInsertL(CLeafDirTreeNode* aNodeToStart, const TDesC& aPath, const TLeafDirData& aLeafDirData, CLeafDirTreeNode*& aNodeInserted)
	{
	CLeafDirTreeNode* currentParent = aNodeToStart;
	TInt foundPos = 0;
	RPointerArray<CLeafDirTreeNode> currentLevel = aNodeToStart->Children();
	TInt currentPos = currentLevel.Count() - 1;
	TPtrC currentPath;
	currentPath.Set(aPath);
	while (currentLevel.Count() > 0 && currentPos >= 0)
		{
		CLeafDirTreeNode* currentNode = currentLevel[currentPos];
		TPtrC currentNodePath;
		currentNodePath.Set(currentNode->Path());

		// If current node is contained by aPath.
		// 	E.g.: current node = "1\2\3\", currentPath = "1\2\3\5\"
		//	In this case, we need to go to next level,
		//	discard logged position (currentPos) in this level as we don't need to come back.
		foundPos = currentPath.FindF(currentNodePath);
		if (foundPos == 0 && currentNodePath.Length() < currentPath.Length())
			{
			currentParent = currentNode;
			currentLevel = currentNode->Children();
			currentPos = currentLevel.Count() - 1;
			currentPath.Set(currentPath.Mid(currentNodePath.Length()));
			continue;
			}

		// If current node's path contains aPath 
		// 	E.g.: current node = "1\2\3\4\", currentPath = "1\2\3\"
		//	We need to split current node to two nodes and return.
		foundPos = currentNodePath.FindF(currentPath);
		if (foundPos == 0 && currentNodePath.Length() > currentPath.Length())
			{
			CLeafDirTreeNode* newNode = CLeafDirTreeNode::NewL(this, currentPath, aLeafDirData, CLeafDirTreeNode::ELeafIntermediary);
			currentParent->MakeItChildL(newNode);
			
			TPtrC restPath;
			restPath.Set(currentNodePath.Mid(currentPath.Length()));
			currentNode->SetPathL(restPath);
			currentParent->RemoveChild(currentNode);
			
			newNode->MakeItChildL(currentNode);
			AddOntoLruL(newNode);
			aNodeInserted = newNode;
			return;
			}

		// If current node's path equals aPath,
		//	change the node type if it is necessary
		if (foundPos == 0 && currentNodePath.Length() == currentPath.Length())
			{
			// Check node type, if already cached, update Lru list and return.
			if (currentNode->IsLeaf() || currentNode->IsLeafIntermediary())
				{
				currentNode->SetLeafDirData(aLeafDirData);
				aNodeInserted = currentNode;
				MakeMostRecentlyUsed(currentNode);
				return;
				}
			// If it has not been cached yet, i.e., it is a 'pure intermediary' node,
			//	cache the node and put it onto Lru list
			else if(currentNode->IsPureIntermediary())
				{
				currentNode->SetLeafDirData(aLeafDirData);
				currentNode->SetType(CLeafDirTreeNode::ELeafIntermediary);
				AddOntoLruL(currentNode);
				aNodeInserted = currentNode;
				return;
				}
			}
		
		// If none of above is the case (i.e. haven't found exact match or paths 
		//	are not contained by each other), we need to find the first common part 
		//	between each child and aPath to share path data.
		foundPos = FindLongestCommonPath(currentNodePath, currentPath);
		// If a common part of path is found, we need to create a pure intermediary node to share
		//	the common part of path data, and create a new leaf node for the target path.
		if (foundPos > 0)
			{
			TPtrC commonPath;
			commonPath.Set(currentNodePath.Left(foundPos + 1));

			currentNodePath.Set(currentNodePath.Mid(foundPos + 1));
			TPtrC newLeafPath;
			newLeafPath.Set(currentPath.Mid(foundPos + 1));

			// Add new pureintermediary node, set it as child of current parent
			TLeafDirData dummyPos(0);
			CLeafDirTreeNode* newPureIntermediaryNode = CLeafDirTreeNode::NewL(this, commonPath, dummyPos, CLeafDirTreeNode::EPureIntermediary);
			currentParent->MakeItChildL(newPureIntermediaryNode);

			// Remove current child from aNodeToStart, do not need to change
			//	node type of aNodeToStart
			currentParent->RemoveChild(currentNode);

			// Modify current pathData, make it child of new node
			newPureIntermediaryNode->MakeItChildL(currentNode);
			currentNode->SetPathL(currentNodePath);

			// Add new leaf node as a child of the new pure intermediary node
			CLeafDirTreeNode* newLeafNode = CLeafDirTreeNode::NewL(this, newLeafPath, aLeafDirData, CLeafDirTreeNode::ELeaf);
			newPureIntermediaryNode->MakeItChildL(newLeafNode);
			aNodeInserted = newLeafNode;
			AddOntoLruL(newLeafNode);
			return;
			}

		// Otherwise, move on within this level.
		currentPos--;
		}
	
	// No match case found, add a new node straight on at current level
	CLeafDirTreeNode* newNode = CLeafDirTreeNode::NewL(this, currentPath, aLeafDirData, CLeafDirTreeNode::ELeaf);

	if (currentParent->IsLeaf())		// might be the root node
		{
		currentParent->SetType(CLeafDirTreeNode::ELeafIntermediary);
		}
	currentParent->MakeItChildL(newNode);
	aNodeInserted = newNode;
	AddOntoLruL(newNode);
	}