aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitaly Buka <vitalybuka@google.com>2016-01-27 11:44:02 -0800
committerVitaly Buka <vitalybuka@google.com>2016-01-27 23:28:25 +0000
commita821f2ec61873d1ad9eb207d7b760b3aaf21248e (patch)
tree8406ed8dba83fd319fb6ff3d74ba3fa1c6ef3d36
parent7d29a5a5402badd1c24a8542539306a521c14cc1 (diff)
downloadlibweave-a821f2ec61873d1ad9eb207d7b760b3aaf21248e.tar.gz
Integrate new macaroon library
Implement validation of auth tokens (no session id check yet). BUG: 26292014 Change-Id: I55c9c8249f6355132486b2be8628c3538d504c5d Reviewed-on: https://weave-review.googlesource.com/2375 Reviewed-by: Alex Vakulenko <avakulenko@google.com>
-rw-r--r--src/privet/auth_manager.cc322
-rw-r--r--src/privet/auth_manager.h9
-rw-r--r--src/privet/auth_manager_unittest.cc46
-rw-r--r--src/privet/openssl_utils.cc10
-rw-r--r--third_party/libuweave/src/crypto_hmac.c51
5 files changed, 273 insertions, 165 deletions
diff --git a/src/privet/auth_manager.cc b/src/privet/auth_manager.cc
index 66d04c4..fd15c21 100644
--- a/src/privet/auth_manager.cc
+++ b/src/privet/auth_manager.cc
@@ -18,6 +18,7 @@
extern "C" {
#include "third_party/libuweave/src/macaroon.h"
+#include "third_party/libuweave/src/macaroon_caveat_internal.h"
}
namespace weave {
@@ -25,10 +26,19 @@ namespace privet {
namespace {
+const time_t kJ2000ToTimeT = 946684800;
const size_t kMaxMacaroonSize = 1024;
const size_t kMaxPendingClaims = 10;
const char kInvalidTokenError[] = "invalid_token";
+uint32_t ToJ2000Time(const base::Time& time) {
+ return std::max(time.ToTimeT(), kJ2000ToTimeT) - kJ2000ToTimeT;
+}
+
+base::Time FromJ2000Time(uint32_t time) {
+ return base::Time::FromTimeT(time + kJ2000ToTimeT);
+}
+
template <class T>
void AppendToArray(T value, std::vector<uint8_t>* array) {
auto begin = reinterpret_cast<const uint8_t*>(&value);
@@ -37,78 +47,86 @@ void AppendToArray(T value, std::vector<uint8_t>* array) {
class Caveat {
public:
- // TODO(vitalybuka): Use _get_buffer_size_ when available.
- Caveat(UwMacaroonCaveatType type, uint32_t value) : buffer(8) {
- CHECK(uw_macaroon_caveat_create_with_uint_(type, value, buffer.data(),
- buffer.size(), &caveat));
- }
-
- // TODO(vitalybuka): Use _get_buffer_size_ when available.
- Caveat(UwMacaroonCaveatType type, const std::string& value)
- : buffer(std::max<size_t>(value.size(), 32u) * 2) {
- CHECK(uw_macaroon_caveat_create_with_str_(
- type, reinterpret_cast<const uint8_t*>(value.data()), value.size(),
- buffer.data(), buffer.size(), &caveat));
+ Caveat(UwMacaroonCaveatType type, size_t str_len)
+ : buffer_(uw_macaroon_caveat_creation_get_buffsize_(type, str_len)) {
+ CHECK(!buffer_.empty());
}
+ const UwMacaroonCaveat& GetCaveat() const { return caveat_; }
- const UwMacaroonCaveat& GetCaveat() const { return caveat; }
-
- private:
- UwMacaroonCaveat caveat;
- std::vector<uint8_t> buffer;
+ protected:
+ UwMacaroonCaveat caveat_{};
+ std::vector<uint8_t> buffer_;
DISALLOW_COPY_AND_ASSIGN(Caveat);
};
-bool CheckCaveatType(const UwMacaroonCaveat& caveat,
- UwMacaroonCaveatType type,
- ErrorPtr* error) {
- UwMacaroonCaveatType caveat_type{};
- if (!uw_macaroon_caveat_get_type_(&caveat, &caveat_type)) {
- return Error::AddTo(error, FROM_HERE, kInvalidTokenError,
- "Unable to get type");
+class ScopeCaveat : public Caveat {
+ public:
+ explicit ScopeCaveat(UwMacaroonCaveatScopeType scope)
+ : Caveat(kUwMacaroonCaveatTypeScope, 0) {
+ CHECK(uw_macaroon_caveat_create_scope_(scope, buffer_.data(),
+ buffer_.size(), &caveat_));
}
- if (caveat_type != type) {
- return Error::AddTo(error, FROM_HERE, kInvalidTokenError,
- "Unexpected caveat type");
+ DISALLOW_COPY_AND_ASSIGN(ScopeCaveat);
+};
+
+class TimestampCaveat : public Caveat {
+ public:
+ explicit TimestampCaveat(const base::Time& timestamp)
+ : Caveat(kUwMacaroonCaveatTypeDelegationTimestamp, 0) {
+ CHECK(uw_macaroon_caveat_create_delegation_timestamp_(
+ ToJ2000Time(timestamp), buffer_.data(), buffer_.size(), &caveat_));
}
- return true;
-}
+ DISALLOW_COPY_AND_ASSIGN(TimestampCaveat);
+};
+
+class ExpirationCaveat : public Caveat {
+ public:
+ explicit ExpirationCaveat(const base::Time& timestamp)
+ : Caveat(kUwMacaroonCaveatTypeExpirationAbsolute, 0) {
+ CHECK(uw_macaroon_caveat_create_expiration_absolute_(
+ ToJ2000Time(timestamp), buffer_.data(), buffer_.size(), &caveat_));
+ }
-bool ReadCaveat(const UwMacaroonCaveat& caveat,
- UwMacaroonCaveatType type,
- uint32_t* value,
- ErrorPtr* error) {
- if (!CheckCaveatType(caveat, type, error))
- return false;
+ DISALLOW_COPY_AND_ASSIGN(ExpirationCaveat);
+};
- if (!uw_macaroon_caveat_get_value_uint_(&caveat, value)) {
- return Error::AddTo(error, FROM_HERE, kInvalidTokenError,
- "Unable to read caveat");
+class UserIdCaveat : public Caveat {
+ public:
+ explicit UserIdCaveat(const std::string& user_id)
+ : Caveat(kUwMacaroonCaveatTypeDelegateeUser, user_id.size()) {
+ CHECK(uw_macaroon_caveat_create_delegatee_user_(
+ reinterpret_cast<const uint8_t*>(user_id.data()), user_id.size(),
+ buffer_.data(), buffer_.size(), &caveat_));
}
- return true;
-}
+ DISALLOW_COPY_AND_ASSIGN(UserIdCaveat);
+};
-bool ReadCaveat(const UwMacaroonCaveat& caveat,
- UwMacaroonCaveatType type,
- std::string* value,
- ErrorPtr* error) {
- if (!CheckCaveatType(caveat, type, error))
- return false;
+// class ServiceCaveat : public Caveat {
+// public:
+// ServiceCaveat() : Caveat(kUwMacaroonCaveatTypeDelegateeService, 0) {
+// // TODO: Replace with service delegatee.
+// CHECK(uw_macaroon_caveat_create_delegatee_user_(
+// nullptr, 0, buffer_.data(), buffer_.size(),
+// &caveat_));
+// }
- const uint8_t* start{nullptr};
- size_t size{0};
- if (!uw_macaroon_caveat_get_value_str_(&caveat, &start, &size)) {
- return Error::AddTo(error, FROM_HERE, kInvalidTokenError,
- "Unable to read caveat");
+// DISALLOW_COPY_AND_ASSIGN(ServiceCaveat);
+// };
+
+class ClientAuthTokenCaveat : public Caveat {
+ public:
+ ClientAuthTokenCaveat()
+ : Caveat(kUwMacaroonCaveatTypeClientAuthorizationTokenV1, 0) {
+ CHECK(uw_macaroon_caveat_create_client_authorization_token_(
+ nullptr, 0, buffer_.data(), buffer_.size(), &caveat_));
}
- value->assign(reinterpret_cast<const char*>(start), size);
- return true;
-}
+ DISALLOW_COPY_AND_ASSIGN(ClientAuthTokenCaveat);
+};
std::vector<uint8_t> CreateSecret() {
std::vector<uint8_t> secret(kSha256OutputSize);
@@ -122,18 +140,53 @@ bool IsClaimAllowed(RootClientTokenOwner curret, RootClientTokenOwner claimer) {
std::vector<uint8_t> CreateMacaroonToken(
const std::vector<uint8_t>& secret,
- const std::vector<UwMacaroonCaveat>& caveats) {
+ const base::Time& time,
+ const std::vector<const UwMacaroonCaveat*>& caveats) {
CHECK_EQ(kSha256OutputSize, secret.size());
+
+ UwMacaroonContext context{};
+ CHECK(uw_macaroon_context_create_(ToJ2000Time(time), nullptr, 0, &context));
+
UwMacaroon macaroon{};
- CHECK(uw_macaroon_new_from_root_key_(&macaroon, secret.data(), secret.size(),
- caveats.data(), caveats.size()));
+ CHECK(uw_macaroon_create_from_root_key_(&macaroon, secret.data(),
+ secret.size(), &context,
+ caveats.data(), caveats.size()));
+
+ std::vector<uint8_t> serialized_token(kMaxMacaroonSize);
+ size_t len = 0;
+ CHECK(uw_macaroon_serialize_(&macaroon, serialized_token.data(),
+ serialized_token.size(), &len));
+ serialized_token.resize(len);
+
+ return serialized_token;
+}
- std::vector<uint8_t> token(kMaxMacaroonSize);
+std::vector<uint8_t> ExtendMacaroonToken(
+ const UwMacaroon& macaroon,
+ const base::Time& time,
+ const std::vector<const UwMacaroonCaveat*>& caveats) {
+ UwMacaroonContext context{};
+ CHECK(uw_macaroon_context_create_(ToJ2000Time(time), nullptr, 0, &context));
+
+ UwMacaroon prev_macaroon = macaroon;
+ std::vector<uint8_t> prev_buffer(kMaxMacaroonSize);
+ std::vector<uint8_t> new_buffer(kMaxMacaroonSize);
+
+ for (auto caveat : caveats) {
+ UwMacaroon new_macaroon{};
+ CHECK(uw_macaroon_extend_(&prev_macaroon, &new_macaroon, &context, caveat,
+ new_buffer.data(), new_buffer.size()));
+ new_buffer.swap(prev_buffer);
+ prev_macaroon = new_macaroon;
+ }
+
+ std::vector<uint8_t> serialized_token(kMaxMacaroonSize);
size_t len = 0;
- CHECK(uw_macaroon_dump_(&macaroon, token.data(), token.size(), &len));
- token.resize(len);
+ CHECK(uw_macaroon_serialize_(&prev_macaroon, serialized_token.data(),
+ serialized_token.size(), &len));
+ serialized_token.resize(len);
- return token;
+ return serialized_token;
}
bool LoadMacaroon(const std::vector<uint8_t>& token,
@@ -141,8 +194,8 @@ bool LoadMacaroon(const std::vector<uint8_t>& token,
UwMacaroon* macaroon,
ErrorPtr* error) {
buffer->resize(kMaxMacaroonSize);
- if (!uw_macaroon_load_(token.data(), token.size(), buffer->data(),
- buffer->size(), macaroon)) {
+ if (!uw_macaroon_deserialize_(token.data(), token.size(), buffer->data(),
+ buffer->size(), macaroon)) {
return Error::AddTo(error, FROM_HERE, kInvalidTokenError,
"Invalid token format");
}
@@ -151,10 +204,16 @@ bool LoadMacaroon(const std::vector<uint8_t>& token,
bool VerifyMacaroon(const std::vector<uint8_t>& secret,
const UwMacaroon& macaroon,
+ const base::Time& time,
+ UwMacaroonValidationResult* result,
ErrorPtr* error) {
CHECK_EQ(kSha256OutputSize, secret.size());
- if (!uw_macaroon_verify_(&macaroon, secret.data(), secret.size())) {
- return Error::AddTo(error, FROM_HERE, "invalid_signature",
+ UwMacaroonContext context = {};
+ CHECK(uw_macaroon_context_create_(ToJ2000Time(time), nullptr, 0, &context));
+
+ if (!uw_macaroon_validate_(&macaroon, secret.data(), secret.size(), &context,
+ result)) {
+ return Error::AddTo(error, FROM_HERE, "invalid_token",
"Invalid token signature");
}
return true;
@@ -239,15 +298,16 @@ AuthManager::~AuthManager() {}
std::vector<uint8_t> AuthManager::CreateAccessToken(const UserInfo& user_info,
base::TimeDelta ttl) const {
- Caveat scope{kUwMacaroonCaveatTypeScope, ToMacaroonScope(user_info.scope())};
- Caveat user{kUwMacaroonCaveatTypeIdentifier, user_info.user_id()};
- Caveat issued{kUwMacaroonCaveatTypeExpiration,
- static_cast<uint32_t>((Now() + ttl).ToTimeT())};
+ ScopeCaveat scope{ToMacaroonScope(user_info.scope())};
+ UserIdCaveat user{user_info.user_id()};
+ const base::Time now = Now();
+ ExpirationCaveat expiration{now + ttl};
return CreateMacaroonToken(
- access_secret_,
+ access_secret_, now,
{
- scope.GetCaveat(), user.GetCaveat(), issued.GetCaveat(),
+ &scope.GetCaveat(), &user.GetCaveat(), &expiration.GetCaveat(),
});
+ return {};
}
bool AuthManager::ParseAccessToken(const std::vector<uint8_t>& token,
@@ -256,35 +316,28 @@ bool AuthManager::ParseAccessToken(const std::vector<uint8_t>& token,
std::vector<uint8_t> buffer;
UwMacaroon macaroon{};
- uint32_t scope{0};
- std::string user_id;
- uint32_t expiration{0};
-
+ UwMacaroonValidationResult result{};
+ const base::Time now = Now();
if (!LoadMacaroon(token, &buffer, &macaroon, error) ||
- !VerifyMacaroon(access_secret_, macaroon, error) ||
macaroon.num_caveats != 3 ||
- !ReadCaveat(macaroon.caveats[0], kUwMacaroonCaveatTypeScope, &scope,
- error) ||
- !ReadCaveat(macaroon.caveats[1], kUwMacaroonCaveatTypeIdentifier,
- &user_id, error) ||
- !ReadCaveat(macaroon.caveats[2], kUwMacaroonCaveatTypeExpiration,
- &expiration, error)) {
+ !VerifyMacaroon(access_secret_, macaroon, now, &result, error)) {
return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthorization,
"Invalid token");
}
- AuthScope auth_scope{FromMacaroonScope(scope)};
+ AuthScope auth_scope{FromMacaroonScope(result.granted_scope)};
if (auth_scope == AuthScope::kNone) {
return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthorization,
"Invalid token data");
}
- base::Time time{base::Time::FromTimeT(expiration)};
- if (time < clock_->Now()) {
- return Error::AddTo(error, FROM_HERE, errors::kAuthorizationExpired,
- "Token is expired");
- }
-
+ // If token is valid and token was not extended, it should has precisely this
+ // values.
+ CHECK_GE(FromJ2000Time(result.expiration_time), now);
+ CHECK_EQ(1u, result.num_delegatees);
+ CHECK(!result.delegatees[0].is_app);
+ std::string user_id{reinterpret_cast<const char*>(result.delegatees[0].id),
+ result.delegatees[0].id_len};
if (user_info)
*user_info = UserInfo{auth_scope, user_id};
@@ -309,7 +362,7 @@ std::vector<uint8_t> AuthManager::ClaimRootClientAuthToken(
std::unique_ptr<AuthManager>{new AuthManager{nullptr, {}}}, owner));
if (pending_claims_.size() > kMaxPendingClaims)
pending_claims_.pop_front();
- return pending_claims_.back().first->GetRootClientAuthToken();
+ return pending_claims_.back().first->GetRootClientAuthToken(owner);
}
bool AuthManager::ConfirmClientAuthToken(const std::vector<uint8_t>& token,
@@ -332,14 +385,22 @@ bool AuthManager::ConfirmClientAuthToken(const std::vector<uint8_t>& token,
return true;
}
-std::vector<uint8_t> AuthManager::GetRootClientAuthToken() const {
- Caveat scope{kUwMacaroonCaveatTypeScope, kUwMacaroonCaveatScopeTypeOwner};
- Caveat issued{kUwMacaroonCaveatTypeIssued,
- static_cast<uint32_t>(Now().ToTimeT())};
- return CreateMacaroonToken(auth_secret_,
- {
- scope.GetCaveat(), issued.GetCaveat(),
- });
+std::vector<uint8_t> AuthManager::GetRootClientAuthToken(
+ RootClientTokenOwner owner) const {
+ CHECK(RootClientTokenOwner::kNone != owner);
+ ClientAuthTokenCaveat auth_token;
+ const base::Time now = Now();
+ TimestampCaveat issued{now};
+
+ UserIdCaveat client{""};
+ // TODO: service caveat when available.
+ // ServiceCaveat cloud;
+
+ return CreateMacaroonToken(
+ auth_secret_, now,
+ {
+ &auth_token.GetCaveat(), &issued.GetCaveat(), &client.GetCaveat(),
+ });
}
base::Time AuthManager::Now() const {
@@ -350,8 +411,9 @@ bool AuthManager::IsValidAuthToken(const std::vector<uint8_t>& token,
ErrorPtr* error) const {
std::vector<uint8_t> buffer;
UwMacaroon macaroon{};
+ UwMacaroonValidationResult result{};
if (!LoadMacaroon(token, &buffer, &macaroon, error) ||
- !VerifyMacaroon(auth_secret_, macaroon, error)) {
+ !VerifyMacaroon(auth_secret_, macaroon, Now(), &result, error)) {
return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthCode,
"Invalid token");
}
@@ -365,19 +427,49 @@ bool AuthManager::CreateAccessTokenFromAuth(
AuthScope* access_token_scope,
base::TimeDelta* access_token_ttl,
ErrorPtr* error) const {
- // TODO(vitalybuka): implement token validation.
- if (!IsValidAuthToken(auth_token, error))
- return false;
+ std::vector<uint8_t> buffer;
+ UwMacaroon macaroon{};
+ UwMacaroonValidationResult result{};
+ const base::Time now = Now();
+ if (!LoadMacaroon(auth_token, &buffer, &macaroon, error) ||
+ !VerifyMacaroon(auth_secret_, macaroon, now, &result, error)) {
+ return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthCode,
+ "Invalid token");
+ }
+
+ AuthScope auth_scope{FromMacaroonScope(result.granted_scope)};
+ if (auth_scope == AuthScope::kNone) {
+ return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthorization,
+ "Invalid token data");
+ }
+
+ // TODO: Integrate black list checks.
+ // TODO: Check session id.
+ auto delegates_rbegin = std::reverse_iterator<const UwMacaroonDelegateeInfo*>(
+ result.delegatees + result.num_delegatees);
+ auto delegates_rend =
+ std::reverse_iterator<const UwMacaroonDelegateeInfo*>(result.delegatees);
+ auto last_user_id =
+ std::find_if(delegates_rbegin, delegates_rend,
+ [](const UwMacaroonDelegateeInfo& delegatee) {
+ return !delegatee.is_app;
+ });
+
+ if (last_user_id == delegates_rend || !last_user_id->id_len) {
+ return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthorization,
+ "User ID is missing");
+ }
+
+ CHECK_GE(FromJ2000Time(result.expiration_time), now);
if (!access_token)
return true;
- // TODO(vitalybuka): User and scope must be parsed from auth_token.
- UserInfo info{config_ ? config_->GetSettings().local_anonymous_access_role
- : AuthScope::kViewer,
- base::GenerateGUID()};
+ std::string user_id{reinterpret_cast<const char*>(last_user_id->id),
+ last_user_id->id_len};
+ UserInfo info{auth_scope, user_id};
- // TODO(vitalybuka): TTL also should be reduced in accordance with auth_token.
+ ttl = std::min(ttl, FromJ2000Time(result.expiration_time) - now);
*access_token = CreateAccessToken(info, ttl);
if (access_token_scope)
@@ -395,5 +487,21 @@ std::vector<uint8_t> AuthManager::CreateSessionId() {
return result;
}
+std::vector<uint8_t> AuthManager::DelegateToUser(
+ const std::vector<uint8_t>& token,
+ const UserInfo& user_info) const {
+ std::vector<uint8_t> buffer;
+ UwMacaroon macaroon{};
+ CHECK(LoadMacaroon(token, &buffer, &macaroon, nullptr));
+
+ ScopeCaveat scope{ToMacaroonScope(user_info.scope())};
+ UserIdCaveat user_caveat{user_info.user_id()};
+
+ return ExtendMacaroonToken(macaroon, Now(),
+ {
+ &scope.GetCaveat(), &user_caveat.GetCaveat(),
+ });
+}
+
} // namespace privet
} // namespace weave
diff --git a/src/privet/auth_manager.h b/src/privet/auth_manager.h
index 309d80e..0fa90a7 100644
--- a/src/privet/auth_manager.h
+++ b/src/privet/auth_manager.h
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
+#include <base/gtest_prod_util.h>
#include <base/time/default_clock.h>
#include <base/time/time.h>
#include <weave/error.h>
@@ -54,7 +55,7 @@ class AuthManager {
bool ConfirmClientAuthToken(const std::vector<uint8_t>& token,
ErrorPtr* error);
- std::vector<uint8_t> GetRootClientAuthToken() const;
+ std::vector<uint8_t> GetRootClientAuthToken(RootClientTokenOwner owner) const;
bool IsValidAuthToken(const std::vector<uint8_t>& token,
ErrorPtr* error) const;
bool CreateAccessTokenFromAuth(const std::vector<uint8_t>& auth_token,
@@ -70,6 +71,12 @@ class AuthManager {
std::vector<uint8_t> CreateSessionId();
private:
+ FRIEND_TEST_ALL_PREFIXES(AuthManagerClaimTest, CreateAccessTokenFromAuth);
+
+ // Test helper.
+ std::vector<uint8_t> DelegateToUser(const std::vector<uint8_t>& token,
+ const UserInfo& user_info) const;
+
Config* config_{nullptr}; // Can be nullptr for tests.
base::DefaultClock default_clock_;
base::Clock* clock_{&default_clock_};
diff --git a/src/privet/auth_manager_unittest.cc b/src/privet/auth_manager_unittest.cc
index 70750ad..c5fba3c 100644
--- a/src/privet/auth_manager_unittest.cc
+++ b/src/privet/auth_manager_unittest.cc
@@ -64,18 +64,18 @@ TEST_F(AuthManagerTest, Constructor) {
}
TEST_F(AuthManagerTest, CreateAccessToken) {
- EXPECT_EQ("UABRUHgcSZDry0bvIsoJv+WDQgEURQJjMjM0RgUaVArkgA==",
+ EXPECT_EQ("WCKDQgEURQlDMjM0RgUaG52hAFA3hFh7TexW1jC96sU4CxvN",
Base64Encode(auth_.CreateAccessToken(
UserInfo{AuthScope::kViewer, "234"}, {})));
- EXPECT_EQ("UL7YEruLg5QQRDIp2+u1cqCDQgEIRQJjMjU3RgUaVArkgA==",
+ EXPECT_EQ("WCKDQgEIRQlDMjU3RgUaG52hAFD3dEHl3Y9Y28uoUESiYuLq",
Base64Encode(auth_.CreateAccessToken(
UserInfo{AuthScope::kManager, "257"}, {})));
- EXPECT_EQ("UPFGeZRanR1wLGYLP5ZDkXiDQgECRQJjNDU2RgUaVArkgA==",
+ EXPECT_EQ("WCKDQgECRQlDNDU2RgUaG52hAFBy35bQdtvlqYf+Y/ANyxLU",
Base64Encode(auth_.CreateAccessToken(
UserInfo{AuthScope::kOwner, "456"}, {})));
auto new_time = clock_.Now() + base::TimeDelta::FromDays(11);
EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(new_time));
- EXPECT_EQ("UMm9KlF3OEtZFBmhScJpl4uDQgEORQJjMzQ1RgUaVBllAA==",
+ EXPECT_EQ("WCKDQgEORQlDMzQ1RgUaG6whgFD1HGVxL8+FPaf/U0bOkXr8",
Base64Encode(auth_.CreateAccessToken(
UserInfo{AuthScope::kUser, "345"}, {})));
}
@@ -137,30 +137,40 @@ TEST_F(AuthManagerTest, ParseAccessToken) {
}
TEST_F(AuthManagerTest, GetRootClientAuthToken) {
- EXPECT_EQ("UK1ACOc3cWGjGBoTIX2bd3qCQgECRgMaVArkgA==",
- Base64Encode(auth_.GetRootClientAuthToken()));
+ EXPECT_EQ("WCCDQxkgAUYIGhudoQBCCUBQn9rT/8iUzwKa0ZIAgCNxyg==",
+ Base64Encode(
+ auth_.GetRootClientAuthToken(RootClientTokenOwner::kClient)));
+}
+
+TEST_F(AuthManagerTest, GetRootClientAuthTokenDifferentOwner) {
+ EXPECT_EQ(
+ "WCCDQxkgAUYIGhudoQBCCUBQn9rT/8iUzwKa0ZIAgCNxyg==",
+ Base64Encode(auth_.GetRootClientAuthToken(RootClientTokenOwner::kCloud)));
}
TEST_F(AuthManagerTest, GetRootClientAuthTokenDifferentTime) {
auto new_time = clock_.Now() + base::TimeDelta::FromDays(15);
EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(new_time));
- EXPECT_EQ("UBpNF8g/GbNUmAyHg1qqJr+CQgECRgMaVB6rAA==",
- Base64Encode(auth_.GetRootClientAuthToken()));
+ EXPECT_EQ("WCCDQxkgAUYIGhuxZ4BCCUBQmNBWA9KdLzxHUCMqzonDZw==",
+ Base64Encode(
+ auth_.GetRootClientAuthToken(RootClientTokenOwner::kClient)));
}
TEST_F(AuthManagerTest, GetRootClientAuthTokenDifferentSecret) {
AuthManager auth{kSecret2, {}, kSecret1, &clock_};
- EXPECT_EQ("UFTBUcgd9d0HnPRnLeroN2mCQgECRgMaVArkgA==",
- Base64Encode(auth.GetRootClientAuthToken()));
+ EXPECT_EQ(
+ "WCCDQxkgAUYIGhudoQBCCUBQQ/BSJs7FEI260RnwjlJrVw==",
+ Base64Encode(auth.GetRootClientAuthToken(RootClientTokenOwner::kClient)));
}
TEST_F(AuthManagerTest, IsValidAuthToken) {
- EXPECT_TRUE(auth_.IsValidAuthToken(auth_.GetRootClientAuthToken(), nullptr));
+ EXPECT_TRUE(auth_.IsValidAuthToken(
+ auth_.GetRootClientAuthToken(RootClientTokenOwner::kClient), nullptr));
// Multiple attempts with random secrets.
for (size_t i = 0; i < 1000; ++i) {
AuthManager auth{{}, {}, {}, &clock_};
- auto token = auth.GetRootClientAuthToken();
+ auto token = auth.GetRootClientAuthToken(RootClientTokenOwner::kClient);
EXPECT_FALSE(auth_.IsValidAuthToken(token, nullptr));
EXPECT_TRUE(auth.IsValidAuthToken(token, nullptr));
}
@@ -245,13 +255,17 @@ TEST_F(AuthManagerClaimTest, CreateAccessTokenFromAuth) {
std::vector<uint8_t> access_token;
AuthScope scope;
base::TimeDelta ttl;
- EXPECT_TRUE(auth_.CreateAccessTokenFromAuth(
- auth_.GetRootClientAuthToken(), base::TimeDelta::FromDays(1),
- &access_token, &scope, &ttl, nullptr));
+ auto root = auth_.GetRootClientAuthToken(RootClientTokenOwner::kClient);
+ auto extended = auth_.DelegateToUser(root, UserInfo{AuthScope::kUser, "234"});
+ EXPECT_TRUE(
+ auth_.CreateAccessTokenFromAuth(extended, base::TimeDelta::FromDays(1),
+ &access_token, &scope, &ttl, nullptr));
UserInfo user_info;
EXPECT_TRUE(auth_.ParseAccessToken(access_token, &user_info, nullptr));
EXPECT_EQ(scope, user_info.scope());
- EXPECT_FALSE(user_info.user_id().empty());
+ EXPECT_EQ(AuthScope::kUser, user_info.scope());
+
+ EXPECT_EQ("234", user_info.user_id());
}
} // namespace privet
diff --git a/src/privet/openssl_utils.cc b/src/privet/openssl_utils.cc
index f38fd1a..17ebf70 100644
--- a/src/privet/openssl_utils.cc
+++ b/src/privet/openssl_utils.cc
@@ -18,13 +18,9 @@ namespace privet {
std::vector<uint8_t> HmacSha256(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& data) {
std::vector<uint8_t> mac(kSha256OutputSize);
- uint8_t hmac_state[uw_crypto_hmac_required_buffer_size_()];
- CHECK(uw_crypto_hmac_init_(hmac_state, sizeof(hmac_state), key.data(),
- key.size()));
- CHECK(uw_crypto_hmac_update_(hmac_state, sizeof(hmac_state), data.data(),
- data.size()));
- CHECK(uw_crypto_hmac_final_(hmac_state, sizeof(hmac_state), mac.data(),
- mac.size()));
+ const UwCryptoHmacMsg messages[] = {{data.data(), data.size()}};
+ CHECK(uw_crypto_hmac_(key.data(), key.size(), messages, arraysize(messages),
+ mac.data(), mac.size()));
return mac;
}
diff --git a/third_party/libuweave/src/crypto_hmac.c b/third_party/libuweave/src/crypto_hmac.c
index 8b75133..d3dca65 100644
--- a/third_party/libuweave/src/crypto_hmac.c
+++ b/third_party/libuweave/src/crypto_hmac.c
@@ -11,41 +11,24 @@
#include <openssl/evp.h>
#include <openssl/hmac.h>
-size_t uw_crypto_hmac_required_buffer_size_() {
- return sizeof(HMAC_CTX);
-}
-
-bool uw_crypto_hmac_init_(uint8_t* state_buffer,
- size_t state_buffer_len,
- const uint8_t* key,
- size_t key_len) {
- if (sizeof(HMAC_CTX) > state_buffer_len) {
+bool uw_crypto_hmac_(const uint8_t* key,
+ size_t key_len,
+ const UwCryptoHmacMsg messages[],
+ size_t num_messages,
+ uint8_t* truncated_digest,
+ size_t truncated_digest_len) {
+ HMAC_CTX context = {0};
+ HMAC_CTX_init(&context);
+ if (!HMAC_Init(&context, key, key_len, EVP_sha256()))
return false;
- }
- HMAC_CTX* context = (HMAC_CTX*)state_buffer;
- HMAC_CTX_init(context);
- return HMAC_Init(context, key, key_len, EVP_sha256());
-}
-bool uw_crypto_hmac_update_(uint8_t* state_buffer,
- size_t state_buffer_len,
- const uint8_t* data,
- size_t data_len) {
- if (sizeof(HMAC_CTX) > state_buffer_len) {
- return false;
- }
- HMAC_CTX* context = (HMAC_CTX*)state_buffer;
- return HMAC_Update(context, data, data_len);
-}
-
-bool uw_crypto_hmac_final_(uint8_t* state_buffer,
- size_t state_buffer_len,
- uint8_t* truncated_digest,
- size_t truncated_digest_len) {
- if (sizeof(HMAC_CTX) > state_buffer_len) {
- return false;
+ for (size_t i = 0; i < num_messages; ++i) {
+ if (messages[i].num_bytes &&
+ (!messages[i].bytes ||
+ !HMAC_Update(&context, messages[i].bytes, messages[i].num_bytes))) {
+ return false;
+ }
}
- HMAC_CTX* context = (HMAC_CTX*)state_buffer;
const size_t kFullDigestLen = (size_t)EVP_MD_size(EVP_sha256());
if (truncated_digest_len > kFullDigestLen) {
@@ -55,8 +38,8 @@ bool uw_crypto_hmac_final_(uint8_t* state_buffer,
uint8_t digest[kFullDigestLen];
uint32_t len = kFullDigestLen;
- bool result = HMAC_Final(context, digest, &len) && kFullDigestLen == len;
- HMAC_CTX_cleanup(context);
+ bool result = HMAC_Final(&context, digest, &len) && kFullDigestLen == len;
+ HMAC_CTX_cleanup(&context);
if (result) {
memcpy(truncated_digest, digest, truncated_digest_len);
}