Beispiel #1
0
  def testWireFormatAccess(self):

    m = rdfvalue.SignedMessageList()

    now = 1369308998000000

    # An unset RDFDatetime with no defaults will be None.
    self.assertEqual(m.timestamp, None)

    # Set the wireformat to the integer equivalent.
    m.SetWireFormat("timestamp", now)

    self.assertTrue(isinstance(m.timestamp, rdfvalue.RDFDatetime))
    self.assertEqual(m.timestamp, now)

    rdf_now = rdfvalue.RDFDatetime().Now()

    m.timestamp = rdf_now
    self.assertEqual(m.GetWireFormat("timestamp"), int(rdf_now))
Beispiel #2
0
    def EncodeMessages(self,
                       message_list,
                       result,
                       destination=None,
                       timestamp=None,
                       api_version=3):
        """Accepts a list of messages and encodes for transmission.

    This function signs and then encrypts the payload.

    Args:
       message_list: A MessageList rdfvalue containing a list of
       GrrMessages.

       result: A ClientCommunication rdfvalue which will be filled in.

       destination: The CN of the remote system this should go to.

       timestamp: A timestamp to use for the signed messages. If None - use the
              current time.

       api_version: The api version which this should be encoded in.

    Returns:
       A nonce (based on time) which is inserted to the encrypted payload. The
       client can verify that the server is able to decrypt the message and
       return the nonce.

    Raises:
       RuntimeError: If we do not support this api version.
    """
        if api_version not in [3]:
            raise RuntimeError("Unsupported api version: %s, expected 3." %
                               api_version)

        if destination is None:
            destination = self.server_name

        # Make a nonce for this transaction
        if timestamp is None:
            self.timestamp = timestamp = long(time.time() * 1000000)

        # Do we have a cached cipher to talk to this destination?
        try:
            cipher = self.cipher_cache.Get(destination)

        except KeyError:
            # Make a new one
            cipher = Cipher(self.common_name, destination, self.private_key,
                            self.pub_key_cache)
            self.cipher_cache.Put(destination, cipher)

        signed_message_list = rdfvalue.SignedMessageList(timestamp=timestamp)
        self.EncodeMessageList(message_list, signed_message_list)

        result.encrypted_cipher_metadata = cipher.encrypted_cipher_metadata

        # Include the encrypted cipher.
        result.encrypted_cipher = cipher.encrypted_cipher

        serialized_message_list = signed_message_list.SerializeToString()

        # Encrypt the message symmetrically.
        # New scheme cipher is signed plus hmac over message list.
        result.packet_iv, result.encrypted = cipher.Encrypt(
            serialized_message_list)

        # This is to support older endpoints.
        result.hmac = cipher.HMAC(result.encrypted)

        # Newer endpoints only look at this HMAC. It is recalculated for each packet
        # in the session. Note that encrypted_cipher and encrypted_cipher_metadata
        # do not change between all packets in this session.
        result.full_hmac = cipher.HMAC(result.encrypted,
                                       result.encrypted_cipher,
                                       result.encrypted_cipher_metadata,
                                       result.packet_iv,
                                       struct.pack("<I", api_version))

        result.api_version = api_version

        if isinstance(result, rdfvalue.RDFValue):
            # Store the number of messages contained.
            result.num_messages = len(message_list)

        return timestamp
Beispiel #3
0
    def DecodeMessages(self, response_comms):
        """Extract and verify server message.

    Args:
        response_comms: A ClientCommunication rdfvalue

    Returns:
       list of messages and the CN where they came from.

    Raises:
       DecryptionError: If the message failed to decrypt properly.
    """
        if response_comms.api_version not in [3]:
            raise DecryptionError("Unsupported api version: %s, expected 3." %
                                  response_comms.api_version)

        if response_comms.encrypted_cipher:
            # Have we seen this cipher before?
            try:
                cipher = self.encrypted_cipher_cache.Get(
                    response_comms.encrypted_cipher)
            except KeyError:
                cipher = ReceivedCipher(response_comms, self.private_key,
                                        self.pub_key_cache)

                if cipher.signature_verified:
                    # Remember it for next time.
                    self.encrypted_cipher_cache.Put(
                        response_comms.encrypted_cipher, cipher)

            # Verify the cipher HMAC with the new response_comms. This will raise
            # DecryptionError if the HMAC does not agree.
            cipher.VerifyHMAC(response_comms)

            # Decrypt the message with the per packet IV.
            plain = cipher.Decrypt(response_comms.encrypted,
                                   response_comms.packet_iv)
            try:
                signed_message_list = rdfvalue.SignedMessageList(plain)
            except rdfvalue.DecodeError as e:
                raise DecryptionError(str(e))

            message_list = self.DecompressMessageList(signed_message_list)

        else:
            # The message is not encrypted. We do not allow unencrypted
            # messages:
            raise DecryptionError("Server response is not encrypted.")

        # Are these messages authenticated?
        auth_state = self.VerifyMessageSignature(response_comms,
                                                 signed_message_list, cipher,
                                                 response_comms.api_version)

        # Mark messages as authenticated and where they came from.
        for msg in message_list.job:
            msg.auth_state = auth_state
            msg.SetWireFormat(
                "source",
                utils.SmartStr(cipher.cipher_metadata.source.Basename()))

        return (message_list.job, cipher.cipher_metadata.source,
                signed_message_list.timestamp)
    def DecodeMessages(self, response_comms):
        """Extract and verify server message.

    Args:
        response_comms: A ClientCommunication rdfvalue

    Returns:
       list of messages and the CN where they came from.

    Raises:
       DecryptionError: If the message failed to decrypt properly.
    """
        if response_comms.api_version not in [3]:
            raise DecryptionError("Unsupported api version.")

        if response_comms.encrypted_cipher:
            # Have we seen this cipher before?
            try:
                cipher = self.encrypted_cipher_cache.Get(
                    response_comms.encrypted_cipher)
            except KeyError:
                cipher = ReceivedCipher(response_comms, self.private_key,
                                        self.pub_key_cache)

                if cipher.signature_verified:
                    # Remember it for next time.
                    self.encrypted_cipher_cache.Put(
                        response_comms.encrypted_cipher, cipher)

            # Add entropy to the PRNG.
            Rand.rand_add(response_comms.encrypted,
                          len(response_comms.encrypted))

            # Check the encrypted message integrity using HMAC.
            if cipher.HMAC(response_comms.encrypted) != response_comms.hmac:
                raise DecryptionError("HMAC verification failed.")

            # Decrypt the messages
            iv = response_comms.iv or cipher.cipher.iv

            plain = cipher.Decrypt(response_comms.encrypted, iv)
            try:
                signed_message_list = rdfvalue.SignedMessageList(plain)
            except rdfvalue.DecodeError as e:
                raise DecryptionError(str(e))

            message_list = self.DecompressMessageList(signed_message_list)

        else:
            # The message is not encrypted. We do not allow unencrypted
            # messages:
            raise DecryptionError("Server response is not encrypted.")

        # Are these messages authenticated?
        auth_state = self.VerifyMessageSignature(response_comms,
                                                 signed_message_list, cipher,
                                                 response_comms.api_version)

        # Mark messages as authenticated and where they came from.
        for msg in message_list.job:
            msg.auth_state = auth_state
            msg.SetWireFormat(
                "source",
                utils.SmartStr(cipher.cipher_metadata.source.Basename()))

        return (message_list.job, cipher.cipher_metadata.source,
                signed_message_list.timestamp)