Generate Root Client Authorization Token

BUG=25934385

Change-Id: Ic7d421f2c0152c7580014229c28495520d8c9981
Reviewed-on: https://weave-review.googlesource.com/1868
Reviewed-by: Vitaly Buka <vitalybuka@google.com>
diff --git a/src/privet/auth_manager.cc b/src/privet/auth_manager.cc
index 0864242..be7e971 100644
--- a/src/privet/auth_manager.cc
+++ b/src/privet/auth_manager.cc
@@ -11,12 +11,18 @@
 #include "src/privet/openssl_utils.h"
 #include "src/string_utils.h"
 
+extern "C" {
+#include "third_party/libuweave/src/macaroon.h"
+}
+
 namespace weave {
 namespace privet {
 
 namespace {
 
 const char kTokenDelimeter[] = ":";
+const size_t kCaveatBuffetSize = 32;
+const size_t kMaxMacaroonSize = 1024;
 
 // Returns "scope:id:time".
 std::string CreateTokenData(const UserInfo& user_info, const base::Time& time) {
@@ -49,6 +55,22 @@
   return UserInfo{static_cast<AuthScope>(scope), id};
 }
 
+class Caveat {
+ public:
+  Caveat(UwMacaroonCaveatType type, uint32_t value) {
+    CHECK(uw_macaroon_caveat_create_with_uint_(type, value, buffer,
+                                               sizeof(buffer), &caveat));
+  }
+
+  const UwMacaroonCaveat& GetCaveat() const { return caveat; }
+
+ private:
+  UwMacaroonCaveat caveat;
+  uint8_t buffer[kCaveatBuffetSize];
+
+  DISALLOW_COPY_AND_ASSIGN(Caveat);
+};
+
 }  // namespace
 
 AuthManager::AuthManager(const std::vector<uint8_t>& secret,
@@ -84,5 +106,26 @@
   return SplitTokenData(std::string(data.begin(), data.end()), time);
 }
 
+std::vector<uint8_t> AuthManager::GetRootDeviceToken(
+    const base::Time& time) const {
+  Caveat scope{kUwMacaroonCaveatTypeScope, kUwMacaroonCaveatScopeTypeOwner};
+  Caveat issued{kUwMacaroonCaveatTypeIssued,
+                static_cast<uint32_t>(time.ToTimeT())};
+
+  UwMacaroonCaveat caveats[] = {
+      scope.GetCaveat(), issued.GetCaveat(),
+  };
+
+  UwMacaroon macaroon{};
+  CHECK(uw_macaroon_new_from_root_key_(
+      &macaroon, secret_.data(), secret_.size(), caveats, arraysize(caveats)));
+
+  std::vector<uint8_t> token(kMaxMacaroonSize);
+  size_t len = 0;
+  CHECK(uw_macaroon_dump_(&macaroon, token.data(), token.size(), &len));
+  token.resize(len);
+  return token;
+}
+
 }  // namespace privet
 }  // namespace weave
diff --git a/src/privet/auth_manager.h b/src/privet/auth_manager.h
index 607b820..8dd6a36 100644
--- a/src/privet/auth_manager.h
+++ b/src/privet/auth_manager.h
@@ -31,6 +31,7 @@
   const std::vector<uint8_t>& GetCertificateFingerprint() const {
     return certificate_fingerprint_;
   }
+  std::vector<uint8_t> GetRootDeviceToken(const base::Time& time) const;
 
  private:
   std::vector<uint8_t> secret_;
diff --git a/src/privet/auth_manager_unittest.cc b/src/privet/auth_manager_unittest.cc
index c3c4ddf..a022538 100644
--- a/src/privet/auth_manager_unittest.cc
+++ b/src/privet/auth_manager_unittest.cc
@@ -25,6 +25,9 @@
   const std::vector<uint8_t> kSecret{69, 53, 17, 37, 80, 73, 2,  5,  79, 64, 41,
                                      57, 12, 54, 65, 63, 72, 74, 93, 81, 20, 95,
                                      89, 3,  94, 92, 27, 21, 49, 90, 36, 6};
+  const std::vector<uint8_t> kSecret2{
+      78, 40, 39, 68, 29, 19, 70, 86, 38, 61, 13, 55, 33, 32, 51, 52,
+      34, 43, 97, 48, 8,  56, 11, 99, 50, 59, 24, 26, 31, 71, 76, 28};
   const std::vector<uint8_t> kFingerprint{
       22, 47, 23, 77, 42, 98, 96, 25,  83, 16, 9, 14, 91, 44, 15, 75,
       60, 62, 10, 18, 82, 35, 88, 100, 30, 45, 7, 46, 67, 84, 58, 85};
@@ -37,7 +40,7 @@
 }
 
 TEST_F(AuthManagerTest, DifferentSecret) {
-  AuthManager auth{{}, {}};
+  AuthManager auth{kSecret2, {}};
   EXPECT_GE(auth.GetSecret().size(), 32u);
   EXPECT_NE(auth_.GetSecret(), auth.GetSecret());
 }
@@ -104,5 +107,22 @@
   }
 }
 
+TEST_F(AuthManagerTest, GetRootDeviceToken) {
+  EXPECT_EQ("UJdl3l856QHDzlohsiGpxseCQgEARgMaVArkgA==",
+            Base64Encode(auth_.GetRootDeviceToken(time_)));
+}
+
+TEST_F(AuthManagerTest, GetRootDeviceTokenDifferentTime) {
+  EXPECT_EQ("UHwWhChuQzQ+yb8gRGURu3GCQgEARgMaVB6rAA==",
+            Base64Encode(auth_.GetRootDeviceToken(
+                time_ + base::TimeDelta::FromDays(15))));
+}
+
+TEST_F(AuthManagerTest, GetRootDeviceTokenDifferentSecret) {
+  AuthManager auth{kSecret2, {}};
+  EXPECT_EQ("UJW4F3R0YMeRctcu8aC6VpyCQgEARgMaVArkgA==",
+            Base64Encode(auth.GetRootDeviceToken(time_)));
+}
+
 }  // namespace privet
 }  // namespace weave
diff --git a/third_party/libuweave/src/macaroon_caveat.c b/third_party/libuweave/src/macaroon_caveat.c
index a04c30d..594f9de 100644
--- a/third_party/libuweave/src/macaroon_caveat.c
+++ b/third_party/libuweave/src/macaroon_caveat.c
@@ -12,7 +12,7 @@
 
 // TODO(bozhu): Find a better way to pre-allocate memory for HMACc computations?
 // Are C99 variable-length arrays allowed on embedded devices?
-#define HMAC_STATE_BUFFER_SIZE 300
+#define HMAC_STATE_BUFFER_SIZE 1024
 
 static bool create_caveat_(UwMacaroonCaveatType type, const void* value,
                            size_t value_len, uint8_t* buffer,
diff --git a/third_party/libuweave/src/macaroon_caveat.h b/third_party/libuweave/src/macaroon_caveat.h
index 5f2c384..78373c8 100644
--- a/third_party/libuweave/src/macaroon_caveat.h
+++ b/third_party/libuweave/src/macaroon_caveat.h
@@ -24,6 +24,13 @@
   kUwMacaroonCaveatTypeSessionIdentifier = 16
 } UwMacaroonCaveatType;
 
+typedef enum {
+  kUwMacaroonCaveatScopeTypeOwner = 0,
+  kUwMacaroonCaveatScopeTypeManager = 1,
+  kUwMacaroonCaveatScopeTypeUser = 2,
+  kUwMacaroonCaveatScopeTypeViewer = 3,
+} UwMacaroonCaveatScopeType;
+
 bool uw_macaroon_caveat_create_without_value_(UwMacaroonCaveatType type,
                                               uint8_t* buffer,
                                               size_t buffer_size,