Home | History | Annotate | Download | only in cup
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <limits>
      6 #include <vector>
      7 
      8 #include "base/base64.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "crypto/random.h"
     11 #include "crypto/secure_util.h"
     12 #include "google_apis/cup/client_update_protocol.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 
     15 namespace {
     16 
     17 std::string GetPublicKeyForTesting() {
     18   // How to generate this key:
     19   //   openssl genpkey -out cr.pem -outform PEM -algorithm RSA
     20   //                   -pkeyopt rsa_keygen_pubexp:3
     21   //   openssl rsa -in cr.pem -pubout -out cr_pub.pem
     22 
     23   static const char kCupTestKey1024_Base64[] =
     24     "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC7ct1JhLSol2DkBcJdNjR3KkEA"
     25     "ZfXpF22lDD2WZu5JAZ4NiZqnHsKGJNPUbCH4AhFsXmuW5wEHhUVNhsMP6F9mQ06D"
     26     "i+ygwZ8aXlklmW4S0Et+SNg3i73fnYn0KDQzrzJnMu46s/CFPhjr4f0TH9b7oHkU"
     27     "XbqNZtG6gwaN1bmzFwIBAw==";
     28 
     29   std::string result;
     30   if (!base::Base64Decode(std::string(kCupTestKey1024_Base64), &result))
     31     return "";
     32 
     33   return result;
     34 }
     35 
     36 }  // end namespace
     37 
     38 #if defined(USE_OPENSSL)
     39 
     40 // Once CUP is implemented for OpenSSL, remove this #if block.
     41 TEST(CupTest, OpenSSLStub) {
     42   scoped_ptr<ClientUpdateProtocol> cup =
     43       ClientUpdateProtocol::Create(8, GetPublicKeyForTesting());
     44   ASSERT_FALSE(cup.get());
     45 }
     46 
     47 #else
     48 
     49 class CupTest : public testing::Test {
     50  protected:
     51   virtual void SetUp() {
     52     cup_ = ClientUpdateProtocol::Create(8, GetPublicKeyForTesting());
     53     ASSERT_TRUE(cup_.get());
     54   }
     55 
     56   void OverrideRAndRebuildKeys() {
     57     // This must be the same length as the modulus of the public key being
     58     // used in the unit test.
     59     static const size_t kPublicKeyLength = 1024 / 8;
     60     static const char kFixedR[] =
     61       "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
     62       "eiusmod tempor incididunt ut labore et dolore magna aliqua.    ";
     63 
     64     ASSERT_EQ(kPublicKeyLength, strlen(kFixedR));
     65     ASSERT_TRUE(cup_->SetSharedKeyForTesting(kFixedR));
     66   }
     67 
     68   ClientUpdateProtocol& CUP() {
     69     return *cup_.get();
     70   }
     71 
     72  private:
     73   scoped_ptr<ClientUpdateProtocol> cup_;
     74 };
     75 
     76 TEST_F(CupTest, GetVersionedSecret) {
     77   // Given a fixed public key set in the test fixture, if the key source |r|
     78   // is filled with known data, |w| can be tested against an expected output,
     79   // and the signing/verification for an given request becomes fixed.
     80   //
     81   // The expected output can be generated using this command line, where
     82   // plaintext.bin is the contents of kFixedR[] in OverrideRAndRebuildKeys():
     83   //
     84   //   openssl rsautl -inkey cr2_pub.pem -pubin -encrypt -raw
     85   //                  -in plaintext.bin | base64
     86   //
     87   // Remember to prepend the key version number, and fix up the Base64
     88   // afterwards to be URL-safe.
     89 
     90   static const char kExpectedVW[] =
     91     "8:lMmNR3mVbOitbq8ceYGStFBwrJcpvY-sauFSbMVe6VONS9x42xTOLY_KdqsWCy"
     92     "KuiJBiQziQLOybPUyA9vk0N5kMnC90LIh2nP2FgFG0M0Z22qjB3drsdJPi7TQZbb"
     93     "Xhqm587M8vjc6VlM_eoC0qYwCPaXBqXjsyiHnXetcn5X0";
     94 
     95   EXPECT_NE(kExpectedVW, CUP().GetVersionedSecret());
     96   OverrideRAndRebuildKeys();
     97   EXPECT_EQ(kExpectedVW, CUP().GetVersionedSecret());
     98 }
     99 
    100 TEST_F(CupTest, SignRequest) {
    101   static const char kUrl[] = "//testserver.chromium.org/update";
    102   static const char kUrlQuery[] = "?junk=present";
    103   static const char kRequest[] = "testbody";
    104 
    105   static const char kExpectedCP[] = "tfjmVMDAbU0-Kye4PjrCuyQIDCU";
    106 
    107   OverrideRAndRebuildKeys();
    108 
    109   // Check the case with no query string other than v|w.
    110   std::string url(kUrl);
    111   url.append("?w=");
    112   url.append(CUP().GetVersionedSecret());
    113 
    114   std::string cp;
    115   ASSERT_TRUE(CUP().SignRequest(url, kRequest, &cp));
    116 
    117   // Check the case with a pre-existing query string.
    118   std::string url2(kUrl);
    119   url2.append(kUrlQuery);
    120   url2.append("&w=");
    121   url2.append(CUP().GetVersionedSecret());
    122 
    123   std::string cp2;
    124   ASSERT_TRUE(CUP().SignRequest(url2, kRequest, &cp2));
    125 
    126   // Changes in the URL should result in changes in the client proof.
    127   EXPECT_EQ(kExpectedCP, cp2);
    128   EXPECT_NE(cp, cp2);
    129 }
    130 
    131 TEST_F(CupTest, ValidateResponse) {
    132   static const char kUrl[] = "//testserver.chromium.orgupdate?junk=present&w=";
    133   static const char kRequest[] = "testbody";
    134 
    135   static const char kGoodResponse[] = "intact_response";
    136   static const char kGoodC[] = "c=EncryptedDataFromTheUpdateServer";
    137   static const char kGoodSP[] = "5rMFMPL9Hgqb-2J8kL3scsHeNgg";
    138 
    139   static const char kBadResponse[] = "tampered_response";
    140   static const char kBadC[] = "c=TotalJunkThatAnAttackerCouldSend";
    141   static const char kBadSP[] = "Base64TamperedShaOneHash";
    142 
    143   OverrideRAndRebuildKeys();
    144 
    145   std::string url(kUrl);
    146   url.append(CUP().GetVersionedSecret());
    147 
    148   std::string client_proof;
    149   ASSERT_TRUE(CUP().SignRequest(url, kRequest, &client_proof));
    150 
    151   // Return true on a valid response and server proof.
    152   EXPECT_TRUE(CUP().ValidateResponse(kGoodResponse, kGoodC, kGoodSP));
    153 
    154   // Return false on anything invalid.
    155   EXPECT_FALSE(CUP().ValidateResponse(kBadResponse, kGoodC, kGoodSP));
    156   EXPECT_FALSE(CUP().ValidateResponse(kGoodResponse, kBadC, kGoodSP));
    157   EXPECT_FALSE(CUP().ValidateResponse(kGoodResponse, kGoodC, kBadSP));
    158   EXPECT_FALSE(CUP().ValidateResponse(kGoodResponse, kBadC, kBadSP));
    159   EXPECT_FALSE(CUP().ValidateResponse(kBadResponse, kGoodC, kBadSP));
    160   EXPECT_FALSE(CUP().ValidateResponse(kBadResponse, kBadC, kGoodSP));
    161   EXPECT_FALSE(CUP().ValidateResponse(kBadResponse, kBadC, kBadSP));
    162 }
    163 
    164 #endif  // !defined(USE_OPENSSL)
    165 
    166