Example #1
0
    def _verify(self, signatureInfo, signedBlob, failureReason):
        """
        Check the type of signatureInfo to get the KeyLocator. Look in the
        IdentityStorage for the public key with the name in the KeyLocator and
        use it to verify the signedBlob. If the public key can't be found,
        return false. (This is a generalized method which can verify both a Data
        packet and an interest.)

        :param Signature signatureInfo: An object of a subclass of Signature,
          e.g. Sha256WithRsaSignature.
        :param SignedBlob signedBlob: the SignedBlob with the signed portion to
          verify.
        :param Array<str> failureReason: If verification fails, set
          failureReason[0] to the failure reason string.
        :return: True if the signature verifies, False if not.
        :rtype: boolean
        """
        publicKeyDer = None
        if KeyLocator.canGetFromSignature(signatureInfo):
            publicKeyDer = self._getPublicKeyDer(
              KeyLocator.getFromSignature(signatureInfo), failureReason)
            if publicKeyDer.isNull():
                return False

        if self.verifySignature(
              signatureInfo, signedBlob, publicKeyDer):
            return True
        else:
            failureReason[0] = (
              "The signature did not verify with the given public key")
            return False
Example #2
0
    def _verify(self, signatureInfo, signedBlob, failureReason):
        """
        Check the type of signatureInfo to get the KeyLocator. Look in the
        IdentityStorage for the public key with the name in the KeyLocator and
        use it to verify the signedBlob. If the public key can't be found,
        return false. (This is a generalized method which can verify both a Data
        packet and an interest.)

        :param Signature signatureInfo: An object of a subclass of Signature,
          e.g. Sha256WithRsaSignature.
        :param SignedBlob signedBlob: the SignedBlob with the signed portion to
          verify.
        :param Array<str> failureReason: If verification fails, set
          failureReason[0] to the failure reason string.
        :return: True if the signature verifies, False if not.
        :rtype: boolean
        """
        publicKeyDer = None
        if KeyLocator.canGetFromSignature(signatureInfo):
            publicKeyDer = self._getPublicKeyDer(
                KeyLocator.getFromSignature(signatureInfo), failureReason)
            if publicKeyDer.isNull():
                return False

        if self.verifySignature(signatureInfo, signedBlob, publicKeyDer):
            return True
        else:
            failureReason[0] = (
                "The signature did not verify with the given public key")
            return False
Example #3
0
    def __str__(self):
        """
        Get a string representation of this certificate.

        :return: The string representation.
        :rtype: str
        """
        result = ""
        result += "Certificate name:\n"
        result += "  " + self.getName().toUri() + "\n"
        result += "Validity:\n"
        result += "  NotBefore: " + Schedule.toIsoString(
            self.getValidityPeriod().getNotBefore()) + "\n"
        result += "  NotAfter: " + Schedule.toIsoString(
            self.getValidityPeriod().getNotAfter()) + "\n"

        # TODO: Print the extension.

        result += "Public key bits:\n"
        try:
            result += Common.base64Encode(self.getPublicKey().toBytes(), True)
        except:
            # No public key.
            pass

        result += "Signature Information:\n"
        result += "  Signature Type: "
        if type(self.getSignature()) is Sha256WithEcdsaSignature:
            result += "SignatureSha256WithEcdsa\n"
        elif type(self.getSignature()) is Sha256WithRsaSignature:
            result += "SignatureSha256WithRsa\n"
        else:
            result += "<unknown>\n"

        if KeyLocator.canGetFromSignature(self.getSignature()):
            result += "  Key Locator: "
            keyLocator = KeyLocator.getFromSignature(self.getSignature())
            if keyLocator.getType() == KeyLocatorType.KEYNAME:
                if keyLocator.getKeyName().equals(self.getKeyName()):
                    result += "Self-Signed "

                result += "Name=" + keyLocator.getKeyName().toUri() + "\n"
            else:
                result += "<no KeyLocator key name>\n"

        return result
Example #4
0
    def __str__(self):
        """
        Get a string representation of this certificate.

        :return: The string representation.
        :rtype: str
        """
        result = ""
        result += "Certificate name:\n"
        result += "  " + self.getName().toUri() + "\n"
        result += "Validity:\n"
        result += "  NotBefore: " + Schedule.toIsoString(
          self.getValidityPeriod().getNotBefore()) + "\n"
        result += "  NotAfter: " + Schedule.toIsoString(
          self.getValidityPeriod().getNotAfter()) + "\n"

        # TODO: Print the extension.

        result += "Public key bits:\n"
        try:
            result += Common.base64Encode(self.getPublicKey().toBytes(), True)
        except:
            # No public key.
            pass

        result += "Signature Information:\n"
        result += "  Signature Type: "
        if isinstance(self.getSignature(), Sha256WithEcdsaSignature):
            result += "SignatureSha256WithEcdsa\n"
        elif isinstance(self.getSignature(), Sha256WithRsaSignature):
            result += "SignatureSha256WithRsa\n"
        else:
            result += "<unknown>\n"

        if KeyLocator.canGetFromSignature(self.getSignature()):
            result += "  Key Locator: "
            keyLocator = KeyLocator.getFromSignature(self.getSignature())
            if keyLocator.getType() == KeyLocatorType.KEYNAME:
                if keyLocator.getKeyName().equals(self.getKeyName()):
                    result += "Self-Signed "

                result += "Name=" + keyLocator.getKeyName().toUri() + "\n"
            else:
                result += "<no KeyLocator key name>\n"

        return result
Example #5
0
    def _getKeyLocatorNameFromSignature(signatureInfo, state):
        """
        A helper method for getKeyLocatorName.

        :param Signature signatureInfo:
        :param ValidationState state:
        :rtype: Name
        """
        if not KeyLocator.canGetFromSignature(signatureInfo):
            state.fail(ValidationError
              (ValidationError.INVALID_KEY_LOCATOR, "KeyLocator is missing"))
            return Name()

        keyLocator = KeyLocator.getFromSignature(signatureInfo)
        if keyLocator.getType() != KeyLocatorType.KEYNAME:
            state.fail(ValidationError
              (ValidationError.INVALID_KEY_LOCATOR, "KeyLocator type is not Name"))
            return Name()

        return keyLocator.getKeyName()
Example #6
0
    def _getKeyLocatorNameFromSignature(signatureInfo, state):
        """
        A helper method for getKeyLocatorName.

        :param Signature signatureInfo:
        :param ValidationState state:
        :rtype: Name
        """
        if not KeyLocator.canGetFromSignature(signatureInfo):
            state.fail(
                ValidationError(ValidationError.INVALID_KEY_LOCATOR,
                                "KeyLocator is missing"))
            return Name()

        keyLocator = KeyLocator.getFromSignature(signatureInfo)
        if keyLocator.getType() != KeyLocatorType.KEYNAME:
            state.fail(
                ValidationError(ValidationError.INVALID_KEY_LOCATOR,
                                "KeyLocator type is not Name"))
            return Name()

        return keyLocator.getKeyName()
    def _verify(self, signatureInfo, signedBlob):
        """
        Check the type of signatureInfo to get the KeyLocator. Look in the
        IdentityStorage for the public key with the name in the KeyLocator and
        use it to verify the signedBlob. If the public key can't be found,
        return false. (This is a generalized method which can verify both a Data
        packet and an interest.)

        :param Signature signatureInfo: An object of a subclass of Signature,
          e.g. Sha256WithRsaSignature.
        :param SignedBlob signedBlob: the SignedBlob with the signed portion to
          verify.
        :return: True if the signature verifies, False if not.
        :rtype: boolean
        """
        publicKeyDer = None
        if KeyLocator.canGetFromSignature(signatureInfo):
            publicKeyDer = self._getPublicKeyDer(KeyLocator.getFromSignature(signatureInfo))
            if publicKeyDer.isNull():
                return False

        return self.verifySignature(signatureInfo, signedBlob, publicKeyDer)
    def _verify(self, signatureInfo, signedBlob):
        """
        Check the type of signatureInfo to get the KeyLocator. Look in the
        IdentityStorage for the public key with the name in the KeyLocator and
        use it to verify the signedBlob. If the public key can't be found,
        return false. (This is a generalized method which can verify both a Data
        packet and an interest.)

        :param Signature signatureInfo: An object of a subclass of Signature,
          e.g. Sha256WithRsaSignature.
        :param SignedBlob signedBlob: the SignedBlob with the signed portion to
          verify.
        :return: True if the signature verifies, False if not.
        :rtype: boolean
        """
        publicKeyDer = None
        if KeyLocator.canGetFromSignature(signatureInfo):
            publicKeyDer = self._getPublicKeyDer(
                KeyLocator.getFromSignature(signatureInfo))
            if publicKeyDer.isNull():
                return False

        return self.verifySignature(signatureInfo, signedBlob, publicKeyDer)
Example #9
0
    def checkVerificationPolicy(self,
                                dataOrInterest,
                                stepCount,
                                onVerified,
                                onValidationFailed,
                                wireFormat=None):
        """
        If there is a rule matching the data or interest, and the matching
        certificate is missing, download it. If there is no matching rule,
        verification fails. Otherwise, verify the signature using the public key
        in the IdentityStorage.

        :param dataOrInterest: The Data object or interest with the signature to
          check.
        :type dataOrInterest: Data or Interest
        :param int stepCount: The number of verification steps that have been
          done, used to track the verification progress.
        :param onVerified: If the signature is verified, this calls
          onVerified(dataOrInterest).
          NOTE: The library will log any exceptions raised by this callback, but
          for better error handling the callback should catch and properly
          handle any exceptions.
        :type onVerified: function object
        :param onValidationFailed: If the signature check fails, this calls
          onValidationFailed(dataOrInterest, reason).
          NOTE: The library will log any exceptions raised by this callback, but
          for better error handling the callback should catch and properly
          handle any exceptions.
        :type onValidationFailed: function object
        :return: None for no further step for looking up a certificate chain.
        :rtype: ValidationRequest
        """
        if stepCount > self._maxDepth:
            try:
                onValidationFailed(
                    dataOrInterest, "The verification stepCount " + stepCount +
                    " exceeded the maxDepth " + self._maxDepth)
            except:
                logging.exception("Error in onValidationFailed")
            return None

        signature = self._extractSignature(dataOrInterest, wireFormat)
        # no signature -> fail
        if signature is None:
            try:
                onValidationFailed(
                    dataOrInterest, "Cannot extract the signature from " +
                    dataOrInterest.getName().toUri())
            except:
                logging.exception("Error in onValidationFailed")
            return None

        if not KeyLocator.canGetFromSignature(signature):
            # We only support signature types with key locators.
            try:
                onValidationFailed(
                    dataOrInterest,
                    "The signature type does not support a KeyLocator")
            except:
                logging.exception("Error in onValidationFailed")
            return None

        keyLocator = None
        try:
            keyLocator = KeyLocator.getFromSignature(signature)
        except Exception as ex:
            # No key locator -> fail.
            try:
                onValidationFailed(
                    dataOrInterest,
                    "Error in KeyLocator.getFromSignature: " + str(ex))
            except:
                logging.exception("Error in onValidationFailed")
            return None

        signatureName = keyLocator.getKeyName()
        # no key name in KeyLocator -> fail
        if signatureName.size() == 0:
            try:
                onValidationFailed(
                    dataOrInterest,
                    "The signature KeyLocator doesn't have a key name")
            except:
                logging.exception("Error in onValidationFailed")
            return None

        objectName = dataOrInterest.getName()
        matchType = "data"

        #for command interests, we need to ignore the last 4 components when matching the name
        if isinstance(dataOrInterest, Interest):
            objectName = objectName.getPrefix(-4)
            matchType = "interest"

        # first see if we can find a rule to match this packet
        try:
            matchedRule = self._findMatchingRule(objectName, matchType)
        except:
            matchedRule = None

        # no matching rule -> fail
        if matchedRule is None:
            try:
                onValidationFailed(
                    dataOrInterest,
                    "No matching rule found for " + objectName.toUri())
            except:
                logging.exception("Error in onValidationFailed")
            return None

        failureReason = ["unknown"]
        signatureMatches = self._checkSignatureMatch(signatureName, objectName,
                                                     matchedRule,
                                                     failureReason)
        if not signatureMatches:
            try:
                onValidationFailed(dataOrInterest, failureReason[0])
            except:
                logging.exception("Error in onValidationFailed")
            return None

        # before we look up keys, refresh any certificate directories
        self._refreshManager.refreshAnchors()

        # now finally check that the data or interest was signed correctly
        # if we don't actually have the certificate yet, create a
        # ValidationRequest for it
        foundCert = self._refreshManager.getCertificate(signatureName)
        if foundCert is None:
            foundCert = self._certificateCache.getCertificate(signatureName)
        if foundCert is None:
            certificateInterest = Interest(signatureName)

            def onCertificateDownloadComplete(data):
                try:
                    certificate = IdentityCertificate(data)
                except:
                    try:
                        onValidationFailed(
                            dataOrInterest, "Cannot decode certificate " +
                            data.getName().toUri())
                    except:
                        logging.exception("Error in onValidationFailed")
                    return None
                self._certificateCache.insertCertificate(certificate)
                self.checkVerificationPolicy(dataOrInterest, stepCount + 1,
                                             onVerified, onValidationFailed)

            nextStep = ValidationRequest(certificateInterest,
                                         onCertificateDownloadComplete,
                                         onValidationFailed, 2, stepCount + 1)

            return nextStep

        # for interests, we must check that the timestamp is fresh enough
        # I do this after (possibly) downloading the certificate to avoid
        # filling the cache with bad keys
        if isinstance(dataOrInterest, Interest):
            keyName = foundCert.getPublicKeyName()
            timestamp = dataOrInterest.getName().get(-4).toNumber()

            if not self._interestTimestampIsFresh(keyName, timestamp,
                                                  failureReason):
                try:
                    onValidationFailed(dataOrInterest, failureReason[0])
                except:
                    logging.exception("Error in onValidationFailed")
                return None

        # certificate is known, verify the signature
        if self._verify(signature, dataOrInterest.wireEncode(), failureReason):
            try:
                onVerified(dataOrInterest)
            except:
                logging.exception("Error in onVerified")
            if isinstance(dataOrInterest, Interest):
                self._updateTimestampForKey(keyName, timestamp)
        else:
            try:
                onValidationFailed(dataOrInterest, failureReason[0])
            except:
                logging.exception("Error in onValidationFailed")
Example #10
0
    def matchesData(self, data, wireFormat=None):
        """
        Check if the given Data packet can satisfy this Interest. This method
        considers the Name, MinSuffixComponents, MaxSuffixComponents,
        PublisherPublicKeyLocator, and Exclude. It does not consider the
        ChildSelector or MustBeFresh. This uses the given wireFormat to get the
        Data packet encoding for the full Name.

        :param Data data: The Data packet to check.
        :param wireFormat: (optional) A WireFormat object used to encode the
          Data packet to get its full Name. If omitted, use
          WireFormat.getDefaultWireFormat().
        :type wireFormat: A subclass of WireFormat
        :return: True if the given Data packet can satisfy this Interest.
        :rtype: bool
        """
        # Imitate ndn-cxx Interest::matchesData.
        interestNameLength = self.getName().size()
        dataName = data.getName()
        fullNameLength = dataName.size() + 1

        # Check MinSuffixComponents.
        hasMinSuffixComponents = (self.getMinSuffixComponents() != None)
        minSuffixComponents = (self.getMinSuffixComponents()
                               if hasMinSuffixComponents else 0)
        if not (interestNameLength + minSuffixComponents <= fullNameLength):
            return False

        # Check MaxSuffixComponents.
        hasMaxSuffixComponents = (self.getMaxSuffixComponents() != None)
        if (hasMaxSuffixComponents
                and not (interestNameLength + self.getMaxSuffixComponents() >=
                         fullNameLength)):
            return False

        # Check the prefix.
        if interestNameLength == fullNameLength:
            if self.getName().get(-1).isImplicitSha256Digest():
                if not self.getName().equals(data.getFullName(wireFormat)):
                    return False
            else:
                # The Interest Name is the same length as the Data full Name,
                #   but the last component isn't a digest so there's no
                #   possibility of matching.
                return False
        else:
            # The Interest Name should be a strict prefix of the Data full Name.
            if not self.getName().isPrefixOf(dataName):
                return False

        # Check the Exclude.
        # The Exclude won't be violated if the Interest Name is the same as the
        #   Data full Name.
        if self.getExclude().size(
        ) > 0 and fullNameLength > interestNameLength:
            if interestNameLength == fullNameLength - 1:
                # The component to exclude is the digest.
                if self.getExclude().matches(
                        data.getFullName(wireFormat).get(interestNameLength)):
                    return False
            else:
                # The component to exclude is not the digest.
                if self.getExclude().matches(dataName.get(interestNameLength)):
                    return False

        # Check the KeyLocator.
        publisherPublicKeyLocator = self.getKeyLocator()
        if publisherPublicKeyLocator.getType() != None:
            signature = data.getSignature()
            if not KeyLocator.canGetFromSignature(signature):
                # No KeyLocator in the Data packet.
                return False
            if not publisherPublicKeyLocator.equals(
                (KeyLocator.getFromSignature(signature))):
                return False

        return True
Example #11
0
    def _getCertificateInterest(self, stepCount, matchType, objectName,
                                signature, failureReason):
        """
        This is a helper for checkVerificationPolicy to verify the rule and
        return a certificate interest to fetch the next certificate in the
        hierarchy if needed.

        :param int stepCount: The number of verification steps that have been
          done, used to track the verification progress.
        :param str matchType: Either "data" or "interest".
        :param Name objectName: The name of the data or interest packet.
        :param Signature signature: The Signature object for the data or
          interest packet.
        :param Array<str> failureReason: If can't determine the interest, set
          failureReason[0] to the failure reason.
        :return: None if can't determine the interest, otherwise the interest
          for the ValidationRequest to fetch the next certificate. However, if
          the interest has an empty name, the validation succeeded and no need
          to fetch a certificate.
        :rtype: Interest
        """
        if stepCount > self._maxDepth:
            failureReason[0] = ("The verification stepCount " + stepCount +
                                " exceeded the maxDepth " + self._maxDepth)
            return None

        # First see if we can find a rule to match this packet.
        try:
            matchedRule = self._findMatchingRule(objectName, matchType)
        except:
            matchedRule = None

        # No matching rule -> fail.
        if matchedRule is None:
            failureReason[
                0] = "No matching rule found for " + objectName.toUri()
            return None

        if not KeyLocator.canGetFromSignature(signature):
            # We only support signature types with key locators.
            failureReason[
                0] = "The signature type does not support a KeyLocator"
            return None

        keyLocator = KeyLocator.getFromSignature(signature)

        signatureName = keyLocator.getKeyName()
        # No key name in KeyLocator -> fail.
        if signatureName.size() == 0:
            failureReason[
                0] = "The signature KeyLocator doesn't have a key name"
            return None

        signatureMatches = self._checkSignatureMatch(signatureName, objectName,
                                                     matchedRule,
                                                     failureReason)
        if not signatureMatches:
            return None

        # Before we look up keys, refresh any certificate directories.
        self._refreshManager.refreshAnchors()

        # If we don't actually have the certificate yet, return a
        #   certificateInterest for it.
        if self._isSecurityV1:
            foundCert = self._refreshManager.getCertificate(signatureName)
            if foundCert is None:
                foundCert = self._certificateCache.getCertificate(
                    signatureName)
            if foundCert is None:
                return Interest(signatureName)
        else:
            foundCert = self._refreshManager.getCertificateV2(signatureName)
            if foundCert is None:
                foundCert = self._certificateCacheV2.find(signatureName)
            if foundCert is None:
                return Interest(signatureName)

        return Interest()
    def _getCertificateInterest(self, stepCount, matchType, objectName,
           signature, failureReason):
        """
        This is a helper for checkVerificationPolicy to verify the rule and
        return a certificate interest to fetch the next certificate in the
        hierarchy if needed.

        :param int stepCount: The number of verification steps that have been
          done, used to track the verification progress.
        :param str matchType: Either "data" or "interest".
        :param Name objectName: The name of the data or interest packet.
        :param Signature signature: The Signature object for the data or
          interest packet.
        :param Array<str> failureReason: If can't determine the interest, set
          failureReason[0] to the failure reason.
        :return: None if can't determine the interest, otherwise the interest
          for the ValidationRequest to fetch the next certificate. However, if
          the interest has an empty name, the validation succeeded and no need
          to fetch a certificate.
        :rtype: Interest
        """
        if stepCount > self._maxDepth:
            failureReason[0] = ("The verification stepCount " + stepCount +
                  " exceeded the maxDepth " + self._maxDepth)
            return None

        # First see if we can find a rule to match this packet.
        try:
            matchedRule = self._findMatchingRule(objectName, matchType)
        except:
            matchedRule = None

        # No matching rule -> fail.
        if matchedRule is None:
            failureReason[0] = "No matching rule found for " + objectName.toUri()
            return None

        if not KeyLocator.canGetFromSignature(signature):
            # We only support signature types with key locators.
            failureReason[0] = "The signature type does not support a KeyLocator"
            return None

        keyLocator = KeyLocator.getFromSignature(signature)

        signatureName = keyLocator.getKeyName()
        # No key name in KeyLocator -> fail.
        if signatureName.size() == 0:
            failureReason[0] = "The signature KeyLocator doesn't have a key name"
            return None

        signatureMatches = self._checkSignatureMatch(
          signatureName, objectName, matchedRule, failureReason)
        if not signatureMatches:
            return None

        # Before we look up keys, refresh any certificate directories.
        self._refreshManager.refreshAnchors()

        # If we don't actually have the certificate yet, return a
        #   certificateInterest for it.
        if self._isSecurityV1:
            foundCert = self._refreshManager.getCertificate(signatureName)
            if foundCert is None:
                foundCert = self._certificateCache.getCertificate(signatureName)
            if foundCert is None:
                return Interest(signatureName)
        else:
            foundCert = self._refreshManager.getCertificateV2(signatureName)
            if foundCert is None:
                foundCert = self._certificateCacheV2.find(signatureName)
            if foundCert is None:
                return Interest(signatureName)

        return Interest()
Example #13
0
    def matchesData(self, data, wireFormat = None):
        """
        Check if the given Data packet can satisfy this Interest. This method
        considers the Name, MinSuffixComponents, MaxSuffixComponents,
        PublisherPublicKeyLocator, and Exclude. It does not consider the
        ChildSelector or MustBeFresh. This uses the given wireFormat to get the
        Data packet encoding for the full Name.

        :param Data data: The Data packet to check.
        :param wireFormat: (optional) A WireFormat object used to encode the
          Data packet to get its full Name. If omitted, use
          WireFormat.getDefaultWireFormat().
        :type wireFormat: A subclass of WireFormat
        :return: True if the given Data packet can satisfy this Interest.
        :rtype: bool
        """
        # Imitate ndn-cxx Interest::matchesData.
        interestNameLength = self.getName().size()
        dataName = data.getName()
        fullNameLength = dataName.size() + 1

        # Check MinSuffixComponents.
        hasMinSuffixComponents = (self.getMinSuffixComponents() != None)
        minSuffixComponents = (self.getMinSuffixComponents() if
          hasMinSuffixComponents else 0)
        if not (interestNameLength + minSuffixComponents <= fullNameLength):
            return False

        # Check MaxSuffixComponents.
        hasMaxSuffixComponents = (self.getMaxSuffixComponents() != None)
        if (hasMaxSuffixComponents and
             not (interestNameLength + self.getMaxSuffixComponents() >= fullNameLength)):
            return False

        # Check the prefix.
        if interestNameLength == fullNameLength:
            if self.getName().get(-1).isImplicitSha256Digest():
                if not self.getName().equals(data.getFullName(wireFormat)):
                    return False
            else:
                # The Interest Name is the same length as the Data full Name,
                #   but the last component isn't a digest so there's no
                #   possibility of matching.
                return False
        else:
            # The Interest Name should be a strict prefix of the Data full Name.
            if not self.getName().isPrefixOf(dataName):
                return False

        # Check the Exclude.
        # The Exclude won't be violated if the Interest Name is the same as the
        #   Data full Name.
        if self.getExclude().size() > 0 and fullNameLength > interestNameLength:
            if interestNameLength == fullNameLength - 1:
                # The component to exclude is the digest.
                if self.getExclude().matches(
                     data.getFullName(wireFormat).get(interestNameLength)):
                    return False
            else:
                # The component to exclude is not the digest.
                if self.getExclude().matches(dataName.get(interestNameLength)):
                    return False

        # Check the KeyLocator.
        publisherPublicKeyLocator = self.getKeyLocator()
        if publisherPublicKeyLocator.getType() != None:
            signature = data.getSignature()
            if not KeyLocator.canGetFromSignature(signature):
                # No KeyLocator in the Data packet.
                return False
            if not publisherPublicKeyLocator.equals(
                  (KeyLocator.getFromSignature(signature))):
                return False

        return True
Example #14
0
    def checkVerificationPolicy(self, dataOrInterest, stepCount, onVerified,
                                onValidationFailed, wireFormat = None):
        """
        If there is a rule matching the data or interest, and the matching
        certificate is missing, download it. If there is no matching rule,
        verification fails. Otherwise, verify the signature using the public key
        in the IdentityStorage.

        :param dataOrInterest: The Data object or interest with the signature to
          check.
        :type dataOrInterest: Data or Interest
        :param int stepCount: The number of verification steps that have been
          done, used to track the verification progress.
        :param onVerified: If the signature is verified, this calls
          onVerified(dataOrInterest).
          NOTE: The library will log any exceptions raised by this callback, but
          for better error handling the callback should catch and properly
          handle any exceptions.
        :type onVerified: function object
        :param onValidationFailed: If the signature check fails, this calls
          onValidationFailed(dataOrInterest, reason).
          NOTE: The library will log any exceptions raised by this callback, but
          for better error handling the callback should catch and properly
          handle any exceptions.
        :type onValidationFailed: function object
        :return: None for no further step for looking up a certificate chain.
        :rtype: ValidationRequest
        """
        if stepCount > self._maxDepth:
            try:
                onValidationFailed(
                  dataOrInterest, "The verification stepCount " + stepCount +
                  " exceeded the maxDepth " + self._maxDepth)
            except:
                logging.exception("Error in onValidationFailed")
            return None

        signature = self._extractSignature(dataOrInterest, wireFormat)
        # no signature -> fail
        if signature is None:
            try:
                onValidationFailed(
                  dataOrInterest, "Cannot extract the signature from " +
                  dataOrInterest.getName().toUri())
            except:
                logging.exception("Error in onValidationFailed")
            return None

        if not KeyLocator.canGetFromSignature(signature):
            # We only support signature types with key locators.
            try:
                onValidationFailed(
                  dataOrInterest,
                  "The signature type does not support a KeyLocator")
            except:
                logging.exception("Error in onValidationFailed")
            return None

        keyLocator = None
        try:
            keyLocator = KeyLocator.getFromSignature(signature)
        except Exception as ex:
            # No key locator -> fail.
            try:
                onValidationFailed(
                  dataOrInterest, "Error in KeyLocator.getFromSignature: " +
                  str(ex))
            except:
                logging.exception("Error in onValidationFailed")
            return None

        signatureName = keyLocator.getKeyName()
        # no key name in KeyLocator -> fail
        if signatureName.size() == 0:
            try:
                onValidationFailed(
                  dataOrInterest,
                  "The signature KeyLocator doesn't have a key name")
            except:
                logging.exception("Error in onValidationFailed")
            return None

        objectName = dataOrInterest.getName()
        matchType = "data"

        #for command interests, we need to ignore the last 4 components when matching the name
        if isinstance(dataOrInterest, Interest):
            objectName = objectName.getPrefix(-4)
            matchType = "interest"

        # first see if we can find a rule to match this packet
        try:
            matchedRule = self._findMatchingRule(objectName, matchType)
        except:
            matchedRule = None

        # no matching rule -> fail
        if matchedRule is None:
            try:
                onValidationFailed(
                  dataOrInterest, "No matching rule found for " +
                  objectName.toUri())
            except:
                logging.exception("Error in onValidationFailed")
            return None

        failureReason = ["unknown"]
        signatureMatches = self._checkSignatureMatch(
          signatureName, objectName, matchedRule, failureReason)
        if not signatureMatches:
            try:
                onValidationFailed(dataOrInterest, failureReason[0])
            except:
                logging.exception("Error in onValidationFailed")
            return None

        # before we look up keys, refresh any certificate directories
        self._refreshManager.refreshAnchors()

        # now finally check that the data or interest was signed correctly
        # if we don't actually have the certificate yet, create a
        # ValidationRequest for it
        foundCert = self._refreshManager.getCertificate(signatureName)
        if foundCert is None:
            foundCert = self._certificateCache.getCertificate(signatureName)
        if foundCert is None:
            certificateInterest = Interest(signatureName)
            def onCertificateDownloadComplete(data):
                try:
                    certificate = IdentityCertificate(data)
                except:
                    try:
                        onValidationFailed(
                          dataOrInterest, "Cannot decode certificate " +
                          data.getName().toUri())
                    except:
                        logging.exception("Error in onValidationFailed")
                    return None
                self._certificateCache.insertCertificate(certificate)
                self.checkVerificationPolicy(dataOrInterest, stepCount+1,
                        onVerified, onValidationFailed)

            nextStep = ValidationRequest(certificateInterest,
                    onCertificateDownloadComplete, onValidationFailed,
                    2, stepCount+1)

            return nextStep

        # for interests, we must check that the timestamp is fresh enough
        # I do this after (possibly) downloading the certificate to avoid
        # filling the cache with bad keys
        if isinstance(dataOrInterest, Interest):
            keyName = foundCert.getPublicKeyName()
            timestamp = dataOrInterest.getName().get(-4).toNumber()

            if not self._interestTimestampIsFresh(
                     keyName, timestamp, failureReason):
                try:
                    onValidationFailed(dataOrInterest, failureReason[0])
                except:
                    logging.exception("Error in onValidationFailed")
                return None

        # certificate is known, verify the signature
        if self._verify(signature, dataOrInterest.wireEncode(), failureReason):
            try:
                onVerified(dataOrInterest)
            except:
                logging.exception("Error in onVerified")
            if isinstance(dataOrInterest, Interest):
                self._updateTimestampForKey(keyName, timestamp)
        else:
            try:
                onValidationFailed(dataOrInterest, failureReason[0])
            except:
                logging.exception("Error in onValidationFailed")