root/net/quic/crypto/crypto_framer_test.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. AsChars
  2. OnError
  3. OnHandshakeMessage
  4. TEST
  5. TEST
  6. TEST
  7. TEST
  8. TEST
  9. TEST
  10. TEST
  11. TEST
  12. TEST
  13. TEST
  14. TEST
  15. TEST
  16. TEST

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <map>
#include <vector>

#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "net/quic/crypto/crypto_framer.h"
#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"

using base::StringPiece;
using std::map;
using std::string;
using std::vector;

namespace net {

namespace {

char* AsChars(unsigned char* data) { return reinterpret_cast<char*>(data); }

}  // namespace

namespace test {

class TestCryptoVisitor : public ::net::CryptoFramerVisitorInterface {
 public:
  TestCryptoVisitor() : error_count_(0) {}

  virtual void OnError(CryptoFramer* framer) OVERRIDE {
    DLOG(ERROR) << "CryptoFramer Error: " << framer->error();
    ++error_count_;
  }

  virtual void OnHandshakeMessage(
      const CryptoHandshakeMessage& message) OVERRIDE {
    messages_.push_back(message);
  }

  // Counters from the visitor callbacks.
  int error_count_;

  vector<CryptoHandshakeMessage> messages_;
};

TEST(CryptoFramerTest, ConstructHandshakeMessage) {
  CryptoHandshakeMessage message;
  message.set_tag(0xFFAA7733);
  message.SetStringPiece(0x12345678, "abcdef");
  message.SetStringPiece(0x12345679, "ghijk");
  message.SetStringPiece(0x1234567A, "lmnopqr");

  unsigned char packet[] = {
    // tag
    0x33, 0x77, 0xAA, 0xFF,
    // num entries
    0x03, 0x00,
    // padding
    0x00, 0x00,
    // tag 1
    0x78, 0x56, 0x34, 0x12,
    // end offset 1
    0x06, 0x00, 0x00, 0x00,
    // tag 2
    0x79, 0x56, 0x34, 0x12,
    // end offset 2
    0x0b, 0x00, 0x00, 0x00,
    // tag 3
    0x7A, 0x56, 0x34, 0x12,
    // end offset 3
    0x12, 0x00, 0x00, 0x00,
    // value 1
    'a',  'b',  'c',  'd',
    'e',  'f',
    // value 2
    'g',  'h',  'i',  'j',
    'k',
    // value 3
    'l',  'm',  'n',  'o',
    'p',  'q',  'r',
  };

  CryptoFramer framer;
  scoped_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
  ASSERT_TRUE(data.get() != NULL);
  test::CompareCharArraysWithHexError("constructed packet", data->data(),
                                      data->length(), AsChars(packet),
                                      arraysize(packet));
}

TEST(CryptoFramerTest, ConstructHandshakeMessageWithTwoKeys) {
  CryptoHandshakeMessage message;
  message.set_tag(0xFFAA7733);
  message.SetStringPiece(0x12345678, "abcdef");
  message.SetStringPiece(0x12345679, "ghijk");

  unsigned char packet[] = {
    // tag
    0x33, 0x77, 0xAA, 0xFF,
    // num entries
    0x02, 0x00,
    // padding
    0x00, 0x00,
    // tag 1
    0x78, 0x56, 0x34, 0x12,
    // end offset 1
    0x06, 0x00, 0x00, 0x00,
    // tag 2
    0x79, 0x56, 0x34, 0x12,
    // end offset 2
    0x0b, 0x00, 0x00, 0x00,
    // value 1
    'a',  'b',  'c',  'd',
    'e',  'f',
    // value 2
    'g',  'h',  'i',  'j',
    'k',
  };

  CryptoFramer framer;
  scoped_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
  ASSERT_TRUE(data.get() != NULL);

  test::CompareCharArraysWithHexError("constructed packet", data->data(),
                                      data->length(), AsChars(packet),
                                      arraysize(packet));
}

TEST(CryptoFramerTest, ConstructHandshakeMessageZeroLength) {
  CryptoHandshakeMessage message;
  message.set_tag(0xFFAA7733);
  message.SetStringPiece(0x12345678, "");

  unsigned char packet[] = {
    // tag
    0x33, 0x77, 0xAA, 0xFF,
    // num entries
    0x01, 0x00,
    // padding
    0x00, 0x00,
    // tag 1
    0x78, 0x56, 0x34, 0x12,
    // end offset 1
    0x00, 0x00, 0x00, 0x00,
  };

  CryptoFramer framer;
  scoped_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
  ASSERT_TRUE(data.get() != NULL);

  test::CompareCharArraysWithHexError("constructed packet", data->data(),
                                      data->length(), AsChars(packet),
                                      arraysize(packet));
}

TEST(CryptoFramerTest, ConstructHandshakeMessageTooManyEntries) {
  CryptoHandshakeMessage message;
  message.set_tag(0xFFAA7733);
  for (uint32 key = 1; key <= kMaxEntries + 1; ++key) {
    message.SetStringPiece(key, "abcdef");
  }

  CryptoFramer framer;
  scoped_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
  EXPECT_TRUE(data.get() == NULL);
}

TEST(CryptoFramerTest, ConstructHandshakeMessageMinimumSize) {
  CryptoHandshakeMessage message;
  message.set_tag(0xFFAA7733);
  message.SetStringPiece(0x01020304, "test");
  message.set_minimum_size(64);

  unsigned char packet[] = {
    // tag
    0x33, 0x77, 0xAA, 0xFF,
    // num entries
    0x02, 0x00,
    // padding
    0x00, 0x00,
    // tag 1
    'P', 'A', 'D', 0,
    // end offset 1
    0x24, 0x00, 0x00, 0x00,
    // tag 2
    0x04, 0x03, 0x02, 0x01,
    // end offset 2
    0x28, 0x00, 0x00, 0x00,
    // 36 bytes of padding.
    '-', '-', '-', '-', '-', '-', '-', '-',
    '-', '-', '-', '-', '-', '-', '-', '-',
    '-', '-', '-', '-', '-', '-', '-', '-',
    '-', '-', '-', '-', '-', '-', '-', '-',
    '-', '-', '-', '-',
    // value 2
    't', 'e', 's', 't',
  };

  CryptoFramer framer;
  scoped_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
  ASSERT_TRUE(data.get() != NULL);

  test::CompareCharArraysWithHexError("constructed packet", data->data(),
                                      data->length(), AsChars(packet),
                                      arraysize(packet));
}

TEST(CryptoFramerTest, ConstructHandshakeMessageMinimumSizePadLast) {
  CryptoHandshakeMessage message;
  message.set_tag(0xFFAA7733);
  message.SetStringPiece(1, "");
  message.set_minimum_size(64);

  unsigned char packet[] = {
    // tag
    0x33, 0x77, 0xAA, 0xFF,
    // num entries
    0x02, 0x00,
    // padding
    0x00, 0x00,
    // tag 1
    0x01, 0x00, 0x00, 0x00,
    // end offset 1
    0x00, 0x00, 0x00, 0x00,
    // tag 2
    'P', 'A', 'D', 0,
    // end offset 2
    0x28, 0x00, 0x00, 0x00,
    // 40 bytes of padding.
    '-', '-', '-', '-', '-', '-', '-', '-',
    '-', '-', '-', '-', '-', '-', '-', '-',
    '-', '-', '-', '-', '-', '-', '-', '-',
    '-', '-', '-', '-', '-', '-', '-', '-',
    '-', '-', '-', '-', '-', '-', '-', '-',
  };

  CryptoFramer framer;
  scoped_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
  ASSERT_TRUE(data.get() != NULL);

  test::CompareCharArraysWithHexError("constructed packet", data->data(),
                                      data->length(), AsChars(packet),
                                      arraysize(packet));
}

TEST(CryptoFramerTest, ProcessInput) {
  test::TestCryptoVisitor visitor;
  CryptoFramer framer;
  framer.set_visitor(&visitor);

  unsigned char input[] = {
    // tag
    0x33, 0x77, 0xAA, 0xFF,
    // num entries
    0x02, 0x00,
    // padding
    0x00, 0x00,
    // tag 1
    0x78, 0x56, 0x34, 0x12,
    // end offset 1
    0x06, 0x00, 0x00, 0x00,
    // tag 2
    0x79, 0x56, 0x34, 0x12,
    // end offset 2
    0x0b, 0x00, 0x00, 0x00,
    // value 1
    'a',  'b',  'c',  'd',
    'e',  'f',
    // value 2
    'g',  'h',  'i',  'j',
    'k',
  };

  EXPECT_TRUE(
      framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
  EXPECT_EQ(0u, framer.InputBytesRemaining());
  EXPECT_EQ(0, visitor.error_count_);
  ASSERT_EQ(1u, visitor.messages_.size());
  const CryptoHandshakeMessage& message = visitor.messages_[0];
  EXPECT_EQ(0xFFAA7733, message.tag());
  EXPECT_EQ(2u, message.tag_value_map().size());
  EXPECT_EQ("abcdef", CryptoTestUtils::GetValueForTag(message, 0x12345678));
  EXPECT_EQ("ghijk", CryptoTestUtils::GetValueForTag(message, 0x12345679));
}

TEST(CryptoFramerTest, ProcessInputWithThreeKeys) {
  test::TestCryptoVisitor visitor;
  CryptoFramer framer;
  framer.set_visitor(&visitor);

  unsigned char input[] = {
    // tag
    0x33, 0x77, 0xAA, 0xFF,
    // num entries
    0x03, 0x00,
    // padding
    0x00, 0x00,
    // tag 1
    0x78, 0x56, 0x34, 0x12,
    // end offset 1
    0x06, 0x00, 0x00, 0x00,
    // tag 2
    0x79, 0x56, 0x34, 0x12,
    // end offset 2
    0x0b, 0x00, 0x00, 0x00,
    // tag 3
    0x7A, 0x56, 0x34, 0x12,
    // end offset 3
    0x12, 0x00, 0x00, 0x00,
    // value 1
    'a',  'b',  'c',  'd',
    'e',  'f',
    // value 2
    'g',  'h',  'i',  'j',
    'k',
    // value 3
    'l',  'm',  'n',  'o',
    'p',  'q',  'r',
  };

  EXPECT_TRUE(
      framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
  EXPECT_EQ(0u, framer.InputBytesRemaining());
  EXPECT_EQ(0, visitor.error_count_);
  ASSERT_EQ(1u, visitor.messages_.size());
  const CryptoHandshakeMessage& message = visitor.messages_[0];
  EXPECT_EQ(0xFFAA7733, message.tag());
  EXPECT_EQ(3u, message.tag_value_map().size());
  EXPECT_EQ("abcdef", CryptoTestUtils::GetValueForTag(message, 0x12345678));
  EXPECT_EQ("ghijk", CryptoTestUtils::GetValueForTag(message, 0x12345679));
  EXPECT_EQ("lmnopqr", CryptoTestUtils::GetValueForTag(message, 0x1234567A));
}

TEST(CryptoFramerTest, ProcessInputIncrementally) {
  test::TestCryptoVisitor visitor;
  CryptoFramer framer;
  framer.set_visitor(&visitor);

  unsigned char input[] = {
    // tag
    0x33, 0x77, 0xAA, 0xFF,
    // num entries
    0x02, 0x00,
    // padding
    0x00, 0x00,
    // tag 1
    0x78, 0x56, 0x34, 0x12,
    // end offset 1
    0x06, 0x00, 0x00, 0x00,
    // tag 2
    0x79, 0x56, 0x34, 0x12,
    // end offset 2
    0x0b, 0x00, 0x00, 0x00,
    // value 1
    'a',  'b',  'c',  'd',
    'e',  'f',
    // value 2
    'g',  'h',  'i',  'j',
    'k',
  };

  for (size_t i = 0; i < arraysize(input); i++) {
    EXPECT_TRUE(framer.ProcessInput(StringPiece(AsChars(input) + i, 1)));
  }
  EXPECT_EQ(0u, framer.InputBytesRemaining());
  ASSERT_EQ(1u, visitor.messages_.size());
  const CryptoHandshakeMessage& message = visitor.messages_[0];
  EXPECT_EQ(0xFFAA7733, message.tag());
  EXPECT_EQ(2u, message.tag_value_map().size());
  EXPECT_EQ("abcdef", CryptoTestUtils::GetValueForTag(message, 0x12345678));
  EXPECT_EQ("ghijk", CryptoTestUtils::GetValueForTag(message, 0x12345679));
}

TEST(CryptoFramerTest, ProcessInputTagsOutOfOrder) {
  test::TestCryptoVisitor visitor;
  CryptoFramer framer;
  framer.set_visitor(&visitor);

  unsigned char input[] = {
    // tag
    0x33, 0x77, 0xAA, 0xFF,
    // num entries
    0x02, 0x00,
    // padding
    0x00, 0x00,
    // tag 1
    0x78, 0x56, 0x34, 0x13,
    // end offset 1
    0x01, 0x00, 0x00, 0x00,
    // tag 2
    0x79, 0x56, 0x34, 0x12,
    // end offset 2
    0x02, 0x00, 0x00, 0x00,
  };

  EXPECT_FALSE(
      framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
  EXPECT_EQ(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, framer.error());
  EXPECT_EQ(1, visitor.error_count_);
}

TEST(CryptoFramerTest, ProcessEndOffsetsOutOfOrder) {
  test::TestCryptoVisitor visitor;
  CryptoFramer framer;
  framer.set_visitor(&visitor);

  unsigned char input[] = {
    // tag
    0x33, 0x77, 0xAA, 0xFF,
    // num entries
    0x02, 0x00,
    // padding
    0x00, 0x00,
    // tag 1
    0x79, 0x56, 0x34, 0x12,
    // end offset 1
    0x01, 0x00, 0x00, 0x00,
    // tag 2
    0x78, 0x56, 0x34, 0x13,
    // end offset 2
    0x00, 0x00, 0x00, 0x00,
  };

  EXPECT_FALSE(
      framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
  EXPECT_EQ(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, framer.error());
  EXPECT_EQ(1, visitor.error_count_);
}

TEST(CryptoFramerTest, ProcessInputTooManyEntries) {
  test::TestCryptoVisitor visitor;
  CryptoFramer framer;
  framer.set_visitor(&visitor);

  unsigned char input[] = {
    // tag
    0x33, 0x77, 0xAA, 0xFF,
    // num entries
    0xA0, 0x00,
    // padding
    0x00, 0x00,
  };

  EXPECT_FALSE(
      framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
  EXPECT_EQ(QUIC_CRYPTO_TOO_MANY_ENTRIES, framer.error());
  EXPECT_EQ(1, visitor.error_count_);
}

TEST(CryptoFramerTest, ProcessInputZeroLength) {
  test::TestCryptoVisitor visitor;
  CryptoFramer framer;
  framer.set_visitor(&visitor);

  unsigned char input[] = {
    // tag
    0x33, 0x77, 0xAA, 0xFF,
    // num entries
    0x02, 0x00,
    // padding
    0x00, 0x00,
    // tag 1
    0x78, 0x56, 0x34, 0x12,
    // end offset 1
    0x00, 0x00, 0x00, 0x00,
    // tag 2
    0x79, 0x56, 0x34, 0x12,
    // end offset 2
    0x05, 0x00, 0x00, 0x00,
  };

  EXPECT_TRUE(
      framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
  EXPECT_EQ(0, visitor.error_count_);
}

}  // namespace test

}  // namespace net

/* [<][>][^][v][top][bottom][index][help] */