예제 #1
0
    def _checkTimestamp(self, state, keyName, timestamp):
        """
        :param ValidationState state: On error, this calls state.fail and
          returns False.
        :param Name keyName: The key name.
        :param float timestamp: The timestamp as milliseconds since Jan 1, 1970 UTC.
        :return: On success, return True. On error, call state.fail and return
          False.
        :rtype: bool
        """
        self._cleanUp()

        # _nowOffsetMilliseconds is only used for testing.
        now = Common.getNowMilliseconds() + self._nowOffsetMilliseconds
        if (timestamp < now - self._options._gracePeriod or
              timestamp > now + self._options._gracePeriod):
            state.fail(ValidationError(ValidationError.POLICY_ERROR,
              "Timestamp is outside the grace period for key " + keyName.toUri()))
            return False

        index = self._findByKeyName(keyName)
        if index >= 0:
            if timestamp <= self._container[index]._timestamp:
                state.fail(ValidationError(ValidationError.POLICY_ERROR,
                  "Timestamp is reordered for key " + keyName.toUri()))
                return False

        def successCallback(interest):
            self._insertNewRecord(interest, keyName, timestamp)

        state.addSuccessCallback(successCallback)

        return True
예제 #2
0
    def _parseCommandInterest(interest, state, keyLocatorName, timestamp):
        """
        Get the keyLocatorName and timestamp from the command interest.

        :param Interest interest: The Interest to parse.
        :param ValidationState state: On error, this calls state.fail and
          returns False.
        :param Array<Name> keyLocatorName: Set keyLocatorName[0] to the
          KeyLocator name.
        :param Array<float> timestamp: Set timestamp[0] to the timestamp as
          milliseconds since Jan 1, 1970 UTC.
        :return: On success, return True. On error, call state.fail and return
          False.
        :rtype: bool
        """
        keyLocatorName[0] = Name()
        timestamp[0] = 0

        name = interest.getName()
        if name.size() < CommandInterestSigner.MINIMUM_SIZE:
            state.fail(
                ValidationError(
                    ValidationError.POLICY_ERROR, "Command interest name `" +
                    interest.getName().toUri() + "` is too short"))
            return False

        timestamp[0] = name.get(CommandInterestSigner.POS_TIMESTAMP).toNumber()

        keyLocatorName[0] = ValidationPolicy.getKeyLocatorName(interest, state)
        if state.isOutcomeFailed():
            # Already failed.
            return False

        return True
예제 #3
0
    def _verifyOriginalPacket(self, trustedCertificate):
        """
        Verify the signature of the original packet. This is only called by the
        Validator class.

        :param CertificateV2 trustedCertificate: The certificate that signs the
          original packet.
        """
        if VerificationHelpers.verifyInterestSignature(self._interest,
                                                       trustedCertificate):
            logging.getLogger(__name__).info("OK signature for interest `" +
                                             self._interest.getName().toUri() +
                                             "`")
            for i in range(len(self._successCallbacks)):
                try:
                    self._successCallbacks[i](self._interest)
                except:
                    logging.exception("Error in successCallback")

            self.setOutcome(True)
        else:
            self.fail(
                ValidationError(
                    ValidationError.INVALID_SIGNATURE,
                    "Invalid signature of interest `" +
                    self._interest.getName().toUri() + "`"))
예제 #4
0
파일: validator.py 프로젝트: tuple71/PyNDN2
    def _validateCertificate(self, certificate, state):
        """
        Recursively validate the certificates in the certification chain.

        :param CertificateV2 certificate: The certificate to check.
        :param ValidationState state: The current validation state.
        """
        logging.getLogger(__name__).info("Start validating certificate " +
                                         certificate.getName().toUri())

        if not certificate.isValid():
            state.fail(
                ValidationError(
                    ValidationError.EXPIRED_CERTIFICATE,
                    "Retrieved certificate is not yet valid or expired `" +
                    certificate.getName().toUri() + "`"))
            return

        def continueValidateCertificate(certificateRequest, state):
            if certificateRequest == None:
                state.fail(
                    ValidationError(
                        ValidationError.POLICY_ERROR,
                        "Validation policy is not allowed to designate `" +
                        certificate.getName().toUri() + "` as a trust anchor"))
            else:
                # We need to fetch the key and validate it.
                state.addCertificate(certificate)
                self._requestCertificate(certificateRequest, state)

        self._policy.checkCertificatePolicy(certificate, state,
                                            continueValidateCertificate)
예제 #5
0
    def checkNames(self, packetName, keyLocatorName, state):
        """
        :param Name packetName:
        :param Name keyLocatorName:
        :param ValidationState state:
        :rtype: bool
        """
        if not self._packetNameRegex.match(packetName):
            state.fail(
                ValidationError(
                    ValidationError.POLICY_ERROR,
                    "The packet " + packetName.toUri() + " (KeyLocator=" +
                    keyLocatorName.toUri() +
                    ") does not match the hyper relation packet name regex " +
                    self._packetNameRegex.getExpr()))
            return False
        if not self._keyNameRegex.match(keyLocatorName):
            state.fail(
                ValidationError(
                    ValidationError.POLICY_ERROR,
                    "The packet " + packetName.toUri() + " (KeyLocator=" +
                    keyLocatorName.toUri() +
                    ") does not match the hyper relation key name regex " +
                    self._keyNameRegex.getExpr()))
            return False

        keyNameMatchExpansion = self._keyNameRegex.expand(
            self._keyNameExpansion)
        packetNameMatchExpansion = self._packetNameRegex.expand(
            self._packetNameExpansion)
        result = ConfigNameRelation.checkNameRelation(
            self._hyperRelation, keyNameMatchExpansion,
            packetNameMatchExpansion)
        if not result:
            state.fail(
                ValidationError(
                    ValidationError.POLICY_ERROR,
                    "KeyLocator check failed: hyper relation " +
                    ConfigNameRelation.toString(self._hyperRelation) +
                    " packet name match=" + packetNameMatchExpansion.toUri() +
                    ", key name match=" + keyNameMatchExpansion.toUri() +
                    " of packet " + packetName.toUri() + " (KeyLocator=" +
                    keyLocatorName.toUri() + ") is invalid"))

        return result
예제 #6
0
    def _checkPolicyHelper(self, keyName, state, continueValidation):
        """
        :param Name keyName:
        :param ValidationState state:
        :param continueValidation:
        :type continueValidation: function object
        """
        try:
            identity = self._pib.getIdentity(
                PibKey.extractIdentityFromKeyName(keyName))
        except Exception as ex:
            state.fail(
                ValidationError(
                    ValidationError.CANNOT_RETRIEVE_CERTIFICATE,
                    "Cannot get the PIB identity for key " + keyName.toUri() +
                    ": " + repr(ex)))
            return

        try:
            key = identity.getKey(keyName)
        except Exception as ex:
            state.fail(
                ValidationError(
                    ValidationError.CANNOT_RETRIEVE_CERTIFICATE,
                    "Cannot get the PIB key " + keyName.toUri() + ": " +
                    repr(ex)))
            return

        try:
            certificate = key.getDefaultCertificate()
        except Exception as ex:
            state.fail(
                ValidationError(
                    ValidationError.CANNOT_RETRIEVE_CERTIFICATE,
                    "Cannot get the default certificate for key " +
                    keyName.toUri() + ": " + repr(ex)))
            return

        # Add the certificate as the temporary trust anchor.
        self._validator.resetAnchors()
        self._validator.loadAnchor("", certificate)
        continueValidation(CertificateRequest(Interest(keyName)), state)
        # Clear the temporary trust anchor.
        self._validator.resetAnchors()
        def onTimeout(interest):
            logging.getLogger(__name__).info(
                "Timeout while fetching certificate " +
                certificateRequest._interest.getName().toUri() + ", retrying")

            certificateRequest._nRetriesLeft -= 1
            if certificateRequest._nRetriesLeft >= 0:
                try:
                    self.fetch(certificateRequest, state, continueValidation)
                except Exception as ex:
                    state.fail(
                        ValidationError(
                            ValidationError.CANNOT_RETRIEVE_CERTIFICATE,
                            "Error in fetch: " + repr(ex)))
            else:
                state.fail(
                    ValidationError(
                        ValidationError.CANNOT_RETRIEVE_CERTIFICATE,
                        "Cannot fetch certificate after all retries `" +
                        certificateRequest._interest.getName().toUri() + "`"))
예제 #8
0
파일: validator.py 프로젝트: tuple71/PyNDN2
 def continueValidateCertificate(certificateRequest, state):
     if certificateRequest == None:
         state.fail(
             ValidationError(
                 ValidationError.POLICY_ERROR,
                 "Validation policy is not allowed to designate `" +
                 certificate.getName().toUri() + "` as a trust anchor"))
     else:
         # We need to fetch the key and validate it.
         state.addCertificate(certificate)
         self._requestCertificate(certificateRequest, state)
예제 #9
0
    def getKeyLocatorName(dataOrInterest, state):
        """
        Extract the KeyLocator Name from a Data or signed Interest packet. The
        SignatureInfo in the packet must contain a KeyLocator of type KEYNAME.
        Otherwise, state.fail is invoked with INVALID_KEY_LOCATOR.

        :param dataOrInterest: The Data or Interest packet with the KeyLocator.
        :type dataOrInterest: Data or Interest
        :param ValidationState state: On error, this calls state.fail and
          returns an empty Name.
        :return: The KeyLocator name, or an empty Name for failure.
        :rtype: Name
        """
        if isinstance(dataOrInterest, Data):
            data = dataOrInterest
            return ValidationPolicy._getKeyLocatorNameFromSignature(
                data.getSignature(), state)
        else:
            interest = dataOrInterest

            name = interest.getName()
            if name.size() < 2:
                state.fail(
                    ValidationError(ValidationError.INVALID_KEY_LOCATOR,
                                    "Invalid signed Interest: name too short"))
                return Name()

            try:
                # TODO: Generalize the WireFormat.
                signatureInfo = WireFormat.getDefaultWireFormat(
                ).decodeSignatureInfoAndValue(
                    interest.getName().get(-2).getValue().buf(),
                    interest.getName().get(-1).getValue().buf())
            except Exception as ex:
                state.fail(
                    ValidationError(ValidationError.INVALID_KEY_LOCATOR,
                                    "Invalid signed Interest: " + repr(ex)))
                return Name()

            return ValidationPolicy._getKeyLocatorNameFromSignature(
                signatureInfo, state)
예제 #10
0
파일: validator.py 프로젝트: tuple71/PyNDN2
    def _requestCertificate(self, certificateRequest, state):
        """
        Request a certificate for further validation.

        :param CertificateRequest certificateRequest: The certificate request.
        :param ValidationState state: The current validation state.
        """
        if state.getDepth() >= self._maxDepth:
            state.fail(
                ValidationError(ValidationError.EXCEEDED_DEPTH_LIMIT,
                                "Exceeded validation depth limit"))
            return

        if state.hasSeenCertificateName(
                certificateRequest._interest.getName()):
            state.fail(
                ValidationError(
                    ValidationError.LOOP_DETECTED,
                    "Validation loop detected for certificate `" +
                    certificateRequest._interest.getName().toUri() + "`"))
            return

        logging.getLogger(__name__).info(
            "Retrieving " + certificateRequest._interest.getName().toUri())

        certificate = self.findTrustedCertificate(certificateRequest._interest)
        if certificate != None:
            logging.getLogger(__name__).info("Found trusted certificate " +
                                             certificate.getName().toUri())

            certificate = state._verifyCertificateChain(certificate)
            if certificate != None:
                state._verifyOriginalPacket(certificate)

            for i in range(len(state._certificateChain)):
                self.cacheVerifiedCertificate(state._certificateChain[i])

            return

        self._certificateFetcher.fetch(certificateRequest, state,
                                       self._validateCertificate)
        def onNetworkNack(interest, networkNack):
            logging.getLogger(
                __name__).info("NACK (" + str(networkNack.getReason()) +
                               ") while fetching certificate " +
                               certificateRequest._interest.getName().toUri())

            certificateRequest._nRetriesLeft -= 1
            if certificateRequest._nRetriesLeft >= 0:
                try:
                    self.fetch(certificateRequest, state, continueValidation)
                except Exception as ex:
                    state.fail(
                        ValidationError(
                            ValidationError.CANNOT_RETRIEVE_CERTIFICATE,
                            "Error in fetch: " + repr(ex)))
            else:
                state.fail(
                    ValidationError(
                        ValidationError.CANNOT_RETRIEVE_CERTIFICATE,
                        "Cannot fetch certificate after all retries `" +
                        certificateRequest._interest.getName().toUri() + "`"))
        def onData(interest, data):
            logging.getLogger(__name__).info(
                "Fetched certificate from network " + data.getName().toUri())

            try:
                certificate = CertificateV2(data)
            except Exception as ex:
                state.fail(
                    ValidationError(
                        ValidationError.MALFORMED_CERTIFICATE,
                        "Fetched a malformed certificate `" +
                        data.getName().toUri() + "` (" + repr(ex) + ")"))
                return

            try:
                continueValidation(certificate, state)
            except Exception as ex:
                state.fail(
                    ValidationError(
                        ValidationError.CANNOT_RETRIEVE_CERTIFICATE,
                        "Error in continueValidation: " + repr(ex)))
예제 #13
0
 def _doFetch(self, certificateRequest, state, continueValidation):
     """
     :type certificateRequest: CertificateRequest
     :type state: TValidationState
     :type continueValidation: function object
     """
     state.fail(
         ValidationError(
             ValidationError.CANNOT_RETRIEVE_CERTIFICATE,
             "Cannot fetch certificate " +
             certificateRequest._interest.getName().toUri() +
             " in offline mode"))
예제 #14
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()
예제 #15
0
    def checkNames(self, packetName, keyLocatorName, state):
        """
        :param Name packetName:
        :param Name keyLocatorName:
        :param ValidationState state:
        :rtype: bool
        """
        result = self._regex.match(keyLocatorName)
        if not result:
            state.fail(
                ValidationError(
                    ValidationError.POLICY_ERROR,
                    "KeyLocator check failed: regex " + self._regex.getExpr() +
                    " for packet " + packetName.toUri() +
                    " is invalid (KeyLocator=" + keyLocatorName.toUri() + ")"))

        return result
예제 #16
0
    def _verifyCertificateChain(self, trustedCertificate):
        """
        Verify signatures of certificates in the certificate chain. On return,
        the certificate chain contains a list of certificates successfully
        verified by trustedCertificate.
        When the certificate chain cannot be verified, this method will call
        fail() with the INVALID_SIGNATURE error code and the appropriate message.
        This is only called by the Validator class.

        :return: The certificate to validate the original data packet, either
          the last entry in the certificate chain or trustedCertificate if the
          certificate chain is empty. However, return None if the signature of
          at least one certificate in the chain is invalid, in which case all
          unverified certificates have been removed from the certificate chain.
        :rtype: CertificateV2
        """
        validatedCertificate = trustedCertificate
        for i in range(len(self._certificateChain)):
            certificateToValidate = self._certificateChain[i]

            if not VerificationHelpers.verifyDataSignature(
                    certificateToValidate, validatedCertificate):
                self.fail(
                    ValidationError(
                        ValidationError.INVALID_SIGNATURE,
                        "Invalid signature of certificate `" +
                        certificateToValidate.getName().toUri() + "`"))
                # Remove this and remaining certificates in the chain.
                while len(self._certificateChain) > i:
                    self._certificateChain.pop(i)

                return None
            else:
                logging.getLogger(__name__).info(
                    "OK signature for certificate `" +
                    certificateToValidate.getName().toUri() + "`")
                validatedCertificate = certificateToValidate

        return validatedCertificate
    def checkPolicy(self, dataOrInterest, state, continueValidation):
        """
        :param dataOrInterest:
        :type dataOrInterest: Data or Interest
        :param ValidationState state:
        :param continueValidation:
        :type continueValidation: function object
        """
        keyLocatorName = ValidationPolicy.getKeyLocatorName(
            dataOrInterest, state)
        if state.isOutcomeFailed():
            # Already called state.fail().
            return

        if keyLocatorName.getPrefix(-2).isPrefixOf(dataOrInterest.getName()):
            continueValidation(CertificateRequest(Interest(keyLocatorName)),
                               state)
        else:
            state.fail(
                ValidationError(
                    ValidationError.INVALID_KEY_LOCATOR,
                    "Signing policy violation for " +
                    dataOrInterest.getName().toUri() + " by " +
                    keyLocatorName.toUri()))
예제 #18
0
    def checkNames(self, packetName, keyLocatorName, state):
        """
        :param Name packetName:
        :param Name keyLocatorName:
        :param ValidationState state:
        :rtype: bool
        """
        # packetName is not used in this check.

        identity = PibKey.extractIdentityFromKeyName(keyLocatorName)
        result = ConfigNameRelation.checkNameRelation(self._relation,
                                                      self._name, identity)
        if not result:
            state.fail(
                ValidationError(
                    ValidationError.POLICY_ERROR,
                    "KeyLocator check failed: name relation " +
                    self._name.toUri() + " " +
                    ConfigNameRelation.toString(self._relation) +
                    " for packet " + packetName.toUri() +
                    " is invalid (KeyLocator=" + keyLocatorName.toUri() +
                    ", identity=" + identity.toUri() + ")"))

        return result
    def _doFetch(self, certificateRequest, state, continueValidation):
        """
        Implement doFetch to use _face.expressInterest to fetch a certificate.

        :param CertificateRequest certificateRequest: The the request with the
          Interest for fetching the certificate.
        :param ValidationState state: The validation state.
        :param continueValidation: After fetching, this calls
          continueValidation(certificate, state) where certificate is the
          fetched certificate and state is the ValidationState.
        :type continueValidation: function object
        """
        def onData(interest, data):
            logging.getLogger(__name__).info(
                "Fetched certificate from network " + data.getName().toUri())

            try:
                certificate = CertificateV2(data)
            except Exception as ex:
                state.fail(
                    ValidationError(
                        ValidationError.MALFORMED_CERTIFICATE,
                        "Fetched a malformed certificate `" +
                        data.getName().toUri() + "` (" + repr(ex) + ")"))
                return

            try:
                continueValidation(certificate, state)
            except Exception as ex:
                state.fail(
                    ValidationError(
                        ValidationError.CANNOT_RETRIEVE_CERTIFICATE,
                        "Error in continueValidation: " + repr(ex)))

        def onTimeout(interest):
            logging.getLogger(__name__).info(
                "Timeout while fetching certificate " +
                certificateRequest._interest.getName().toUri() + ", retrying")

            certificateRequest._nRetriesLeft -= 1
            if certificateRequest._nRetriesLeft >= 0:
                try:
                    self.fetch(certificateRequest, state, continueValidation)
                except Exception as ex:
                    state.fail(
                        ValidationError(
                            ValidationError.CANNOT_RETRIEVE_CERTIFICATE,
                            "Error in fetch: " + repr(ex)))
            else:
                state.fail(
                    ValidationError(
                        ValidationError.CANNOT_RETRIEVE_CERTIFICATE,
                        "Cannot fetch certificate after all retries `" +
                        certificateRequest._interest.getName().toUri() + "`"))

        def onNetworkNack(interest, networkNack):
            logging.getLogger(
                __name__).info("NACK (" + str(networkNack.getReason()) +
                               ") while fetching certificate " +
                               certificateRequest._interest.getName().toUri())

            certificateRequest._nRetriesLeft -= 1
            if certificateRequest._nRetriesLeft >= 0:
                try:
                    self.fetch(certificateRequest, state, continueValidation)
                except Exception as ex:
                    state.fail(
                        ValidationError(
                            ValidationError.CANNOT_RETRIEVE_CERTIFICATE,
                            "Error in fetch: " + repr(ex)))
            else:
                state.fail(
                    ValidationError(
                        ValidationError.CANNOT_RETRIEVE_CERTIFICATE,
                        "Cannot fetch certificate after all retries `" +
                        certificateRequest._interest.getName().toUri() + "`"))

        try:
            self._face.expressInterest(certificateRequest._interest, onData,
                                       onTimeout, onNetworkNack)
        except Exception as ex:
            state.fail(
                ValidationError(ValidationError.CANNOT_RETRIEVE_CERTIFICATE,
                                "Error in expressInterest: " + repr(ex)))
예제 #20
0
    def checkPolicy(self, dataOrInterest, state, continueValidation):
        """
        :param dataOrInterest:
        :type dataOrInterest: Data or Interest
        :param ValidationState state:
        :param continueValidation:
        :type continueValidation: function object
        """
        if self.hasInnerPolicy():
            raise ValidatorConfigError(
                "ValidationPolicyConfig must be a terminal inner policy")

        if self._shouldBypass:
            continueValidation(None, state)
            return

        keyLocatorName = ValidationPolicy.getKeyLocatorName(
            dataOrInterest, state)
        if state.isOutcomeFailed():
            # Already called state.fail() .
            return

        if isinstance(dataOrInterest, Data):
            data = dataOrInterest

            for i in range(len(self._dataRules)):
                rule = self._dataRules[i]

                if rule.match(False, data.getName()):
                    if rule.check(False, data.getName(), keyLocatorName,
                                  state):
                        continueValidation(
                            CertificateRequest(Interest(keyLocatorName)),
                            state)
                        return
                    else:
                        # rule.check failed and already called state.fail() .
                        return

            state.fail(
                ValidationError(
                    ValidationError.POLICY_ERROR,
                    "No rule matched for data `" + data.getName().toUri() +
                    "`"))
        else:
            interest = dataOrInterest

            for i in range(len(self._interestRules)):
                rule = self._interestRules[i]

                if rule.match(True, interest.getName()):
                    if rule.check(True, interest.getName(), keyLocatorName,
                                  state):
                        continueValidation(
                            CertificateRequest(Interest(keyLocatorName)),
                            state)
                        return
                    else:
                        # rule.check failed and already called state.fail() .
                        return

            state.fail(
                ValidationError(
                    ValidationError.POLICY_ERROR,
                    "No rule matched for interest `" +
                    interest.getName().toUri() + "`"))