diff options
author | Vitaly Buka <vitalybuka@google.com> | 2016-01-27 11:44:02 -0800 |
---|---|---|
committer | Vitaly Buka <vitalybuka@google.com> | 2016-01-27 23:28:25 +0000 |
commit | a821f2ec61873d1ad9eb207d7b760b3aaf21248e (patch) | |
tree | 8406ed8dba83fd319fb6ff3d74ba3fa1c6ef3d36 | |
parent | 7d29a5a5402badd1c24a8542539306a521c14cc1 (diff) | |
download | libweave-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.cc | 322 | ||||
-rw-r--r-- | src/privet/auth_manager.h | 9 | ||||
-rw-r--r-- | src/privet/auth_manager_unittest.cc | 46 | ||||
-rw-r--r-- | src/privet/openssl_utils.cc | 10 | ||||
-rw-r--r-- | third_party/libuweave/src/crypto_hmac.c | 51 |
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); } |